1
0
mirror of https://github.com/samba-team/samba.git synced 2024-12-22 13:34:15 +03:00

merged more updates from Jim Myers

(This used to be commit 03bf306596)
This commit is contained in:
Andrew Tridgell 2003-12-04 11:01:58 +00:00
parent 2e5ae6f065
commit 42c6a2548a
7 changed files with 662 additions and 53 deletions

View File

@ -292,7 +292,7 @@ SMBD_OBJ_SRV = smbd/connection.o \
smbd/password.o smbd/conn.o \
smbd/negprot.o smbd/request.o \
smbd/reply.o smbd/sesssetup.o \
smbd/trans2.o \
smbd/trans2.o smbd/search.o smbd/nttrans.o \
lib/sysacls.o lib/server_mutex.o \
smbd/build_options.o smbd/service.o \
smbd/rewrite.o \

View File

@ -178,7 +178,8 @@ NTSTATUS ntvfs_map_open(struct request_context *req, union smb_open *io)
break;
case OPEN_FLAGS_OPEN_RDWR:
case 0xf: /* FCB mode */
io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_ALL_ACCESS;
io2.generic.in.access_mask = GENERIC_RIGHTS_FILE_READ |
GENERIC_RIGHTS_FILE_WRITE;
io->open.out.rmode = DOS_OPEN_RDWR; /* assume we got r/w */
break;
default:
@ -369,12 +370,13 @@ NTSTATUS ntvfs_map_fsinfo(struct request_context *req, union smb_fsinfo *fs)
*/
NTSTATUS ntvfs_map_fileinfo(struct request_context *req, union smb_fileinfo *info, union smb_fileinfo *info2)
{
int i;
/* and convert it to the required level using results in info2 */
switch (info->generic.level) {
case RAW_FILEINFO_GENERIC:
return NT_STATUS_INVALID_LEVEL;
case RAW_FILEINFO_GETATTR:
info->getattr.out.attrib = info2->generic.out.attrib & 0x3f;
info->getattr.out.attrib = info2->generic.out.attrib & 0xff;
info->getattr.out.size = info2->generic.out.size;
info->getattr.out.write_time = nt_time_to_unix(&info2->generic.out.write_time);
return NT_STATUS_OK;
@ -468,29 +470,118 @@ NTSTATUS ntvfs_map_fileinfo(struct request_context *req, union smb_fileinfo *inf
case RAW_FILEINFO_STREAM_INFO:
case RAW_FILEINFO_STREAM_INFORMATION:
/* setup a single data stream */
info->stream_info.out.num_streams = info2->generic.out.num_streams;
info->stream_info.out.streams = talloc(req->mem_ctx, sizeof(info2->stream_info.out.streams[0]));
if (!info->stream_info.out.streams) {
return NT_STATUS_NO_MEMORY;
if (info->stream_info.out.num_streams > 0) {
info->stream_info.out.streams = talloc(req->mem_ctx,
info->stream_info.out.num_streams * sizeof(struct stream_struct));
if (!info->stream_info.out.streams) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for %d streams\n",
info->stream_info.out.num_streams));
return NT_STATUS_NO_MEMORY;
}
for (i=0; i < info->stream_info.out.num_streams; i++) {
info->stream_info.out.streams[i] = info2->generic.out.streams[i];
info->stream_info.out.streams[i].stream_name.s =
talloc_strdup(req->mem_ctx, info2->generic.out.streams[i].stream_name.s);
if (!info->stream_info.out.streams[i].stream_name.s) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
return NT_STATUS_NO_MEMORY;
}
}
}
info->stream_info.out.streams[0].size = info2->generic.out.streams[0].size;
info->stream_info.out.streams[0].alloc_size = info2->generic.out.streams[0].alloc_size;
info->stream_info.out.streams[0].stream_name.s = info2->generic.out.streams[0].stream_name.s;
info->stream_info.out.streams[0].stream_name.private_length = info->generic.out.streams[0].stream_name.private_length;
return NT_STATUS_OK;
case RAW_FILEINFO_NAME_INFO:
case RAW_FILEINFO_NAME_INFORMATION:
info->name_info.out.fname.s = info2->generic.out.fname.s;
info->name_info.out.fname.s = talloc_strdup(req->mem_ctx, info2->generic.out.fname.s);
info->name_info.out.fname.private_length = info2->generic.out.fname.private_length;
return NT_STATUS_OK;
case RAW_FILEINFO_ALT_NAME_INFO:
case RAW_FILEINFO_ALT_NAME_INFORMATION:
info->alt_name_info.out.fname.s = info2->generic.out.alt_fname.s;
info->alt_name_info.out.fname.s = talloc_strdup(req->mem_ctx, info2->generic.out.alt_fname.s);
info->alt_name_info.out.fname.private_length = info2->generic.out.alt_fname.private_length;
return NT_STATUS_OK;
case RAW_FILEINFO_POSITION_INFORMATION:
info->position_information.out.position = info2->generic.out.position;
return NT_STATUS_OK;
case RAW_FILEINFO_ALL_EAS:
info->all_eas.out.num_eas = info2->generic.out.num_eas;
if (info->all_eas.out.num_eas > 0) {
info->all_eas.out.eas = talloc(req->mem_ctx,
info->all_eas.out.num_eas * sizeof(struct ea_struct));
if (!info->all_eas.out.eas) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for %d eas\n",
info->all_eas.out.num_eas));
return NT_STATUS_NO_MEMORY;
}
for (i = 0; i < info->all_eas.out.num_eas; i++) {
info->all_eas.out.eas[i] = info2->generic.out.eas[i];
info->all_eas.out.eas[i].name.s =
talloc_strdup(req->mem_ctx, info2->generic.out.eas[i].name.s);
if (!info->all_eas.out.eas[i].name.s) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
return NT_STATUS_NO_MEMORY;
}
info->all_eas.out.eas[i].value.data =
talloc_memdup(req->mem_ctx,
info2->generic.out.eas[i].value.data,
info2->generic.out.eas[i].value.length);
if (!info->all_eas.out.eas[i].value.data) {
DEBUG(2,("ntvfs_map_fileinfo: no memory for stream_name\n"));
return NT_STATUS_NO_MEMORY;
}
}
}
return NT_STATUS_OK;
case RAW_FILEINFO_IS_NAME_VALID:
return NT_STATUS_OK;
case RAW_FILEINFO_COMPRESSION_INFO:
case RAW_FILEINFO_COMPRESSION_INFORMATION:
info->compression_info.out.compressed_size = info2->generic.out.compressed_size;
info->compression_info.out.format = info2->generic.out.format;
info->compression_info.out.unit_shift = info2->generic.out.unit_shift;
info->compression_info.out.chunk_shift = info2->generic.out.chunk_shift;
info->compression_info.out.cluster_shift = info2->generic.out.cluster_shift;
return NT_STATUS_OK;
case RAW_FILEINFO_ACCESS_INFORMATION:
info->access_information.out.access_flags = info2->generic.out.access_flags;
return NT_STATUS_OK;
case RAW_FILEINFO_MODE_INFORMATION:
info->mode_information.out.mode = info2->generic.out.mode;
return NT_STATUS_OK;
case RAW_FILEINFO_ALIGNMENT_INFORMATION:
info->alignment_information.out.alignment_requirement =
info2->generic.out.alignment_requirement;
return NT_STATUS_OK;
#if 0
case RAW_FILEINFO_UNIX_BASIC:
info->unix_basic_info.out.end_of_file = info2->generic.out.end_of_file;
info->unix_basic_info.out.num_bytes = info2->generic.out.size;
info->unix_basic_info.out.status_change_time = info2->generic.out.change_time;
info->unix_basic_info.out.access_time = info2->generic.out.access_time;
info->unix_basic_info.out.change_time = info2->generic.out.change_time;
info->unix_basic_info.out.uid = info2->generic.out.uid;
info->unix_basic_info.out.gid = info2->generic.out.gid;
info->unix_basic_info.out.file_type = info2->generic.out.file_type;
info->unix_basic_info.out.dev_major = info2->generic.out.device;
info->unix_basic_info.out.dev_minor = info2->generic.out.device;
info->unix_basic_info.out.unique_id = info2->generic.out.inode;
info->unix_basic_info.out.permissions = info2->generic.out.permissions;
info->unix_basic_info.out.nlink = info2->generic.out.nlink;
return NT_STATUS_OK;
case RAW_FILEINFO_UNIX_LINK:
info->unix_link_info.out.link_dest = info2->generic.out.link_dest;
return NT_STATUS_OK;
#endif
}
return NT_STATUS_INVALID_LEVEL;

273
source4/smbd/nttrans.c Normal file
View File

@ -0,0 +1,273 @@
/*
Unix SMB/CIFS implementation.
NT transaction handling
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.
*/
/*
This file handles the parsing of transact2 requests
*/
#include "includes.h"
#define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ((blob)->length < (size)) { \
return NT_STATUS_INFO_LENGTH_MISMATCH; \
}} while (0)
/* setup a nttrans reply, given the data and params sizes */
static void nttrans_setup_reply(struct request_context *req,
struct smb_nttrans *trans,
uint16 param_size, uint16 data_size,
uint16 setup_count)
{
trans->out.setup_count = setup_count;
if (setup_count != 0) {
trans->out.setup = talloc_zero(req->mem_ctx, sizeof(uint16) * setup_count);
}
trans->out.params = data_blob_talloc(req->mem_ctx, NULL, param_size);
trans->out.data = data_blob_talloc(req->mem_ctx, NULL, data_size);
}
/* parse NTTRANS_CREATE request
*/
static NTSTATUS nttrans_create(struct request_context *req,
struct smb_nttrans *trans)
{
return NT_STATUS_FOOBAR;
}
/* parse NTTRANS_RENAME request
*/
static NTSTATUS nttrans_rename(struct request_context *req,
struct smb_nttrans *trans)
{
return NT_STATUS_FOOBAR;
}
/* parse NTTRANS_IOCTL request
*/
static NTSTATUS nttrans_ioctl(struct request_context *req,
struct smb_nttrans *trans)
{
union smb_ioctl nt;
uint32 function;
uint16 fnum;
uint8 filter;
BOOL fsctl;
DATA_BLOB *blob;
/* should have at least 4 setup words */
if (trans->in.setup_count != 4) {
return NT_STATUS_INVALID_PARAMETER;
}
function = IVAL(trans->in.setup, 0);
fnum = SVAL(trans->in.setup, 4);
fsctl = CVAL(trans->in.setup, 6);
filter = CVAL(trans->in.setup, 7);
blob = &trans->in.data;
nt.ntioctl.level = RAW_IOCTL_NTIOCTL;
nt.ntioctl.in.fnum = fnum;
nt.ntioctl.in.function = function;
nt.ntioctl.in.fsctl = fsctl;
nt.ntioctl.in.filter = filter;
nttrans_setup_reply(req, trans, 0, 0, 1);
trans->out.setup[0] = 0;
return req->conn->ntvfs_ops->ioctl(req, &nt);
}
/*
backend for nttrans requests
*/
static NTSTATUS nttrans_backend(struct request_context *req,
struct smb_nttrans *trans)
{
DEBUG(9,("nttrans_backend: setup_count=%d function=%d\n",
trans->in.setup_count, trans->in.function));
/* must have at least one setup word */
if (trans->in.setup_count < 1) {
return NT_STATUS_FOOBAR;
}
/* the nttrans command is in function */
switch (trans->in.function) {
case NT_TRANSACT_CREATE:
return nttrans_create(req, trans);
case NT_TRANSACT_IOCTL:
return nttrans_ioctl(req, trans);
case NT_TRANSACT_RENAME:
return nttrans_rename(req, trans);
}
/* an unknown nttrans command */
return NT_STATUS_FOOBAR;
}
/****************************************************************************
Reply to an SMBnttrans request
****************************************************************************/
void reply_nttrans(struct request_context *req)
{
struct smb_nttrans trans;
int i;
uint16 param_ofs, data_ofs;
uint16 param_count, data_count;
uint16 params_left, data_left;
uint16 param_total, data_total;
char *params, *data;
NTSTATUS status;
/* parse request */
if (req->in.wct < 19) {
req_reply_error(req, NT_STATUS_FOOBAR);
return;
}
trans.in.max_setup = CVAL(req->in.vwv, 0);
param_total = IVAL(req->in.vwv, 3);
data_total = IVAL(req->in.vwv, 7);
trans.in.max_param = IVAL(req->in.vwv, 11);
trans.in.max_data = IVAL(req->in.vwv, 15);
param_count = IVAL(req->in.vwv, 19);
param_ofs = IVAL(req->in.vwv, 23);
data_count = IVAL(req->in.vwv, 27);
data_ofs = IVAL(req->in.vwv, 31);
trans.in.setup_count = CVAL(req->in.vwv, 35);
trans.in.function = SVAL(req->in.vwv, 36);
if (req->in.wct != 19 + trans.in.setup_count) {
req_reply_dos_error(req, ERRSRV, ERRerror);
return;
}
/* parse out the setup words */
trans.in.setup = talloc(req->mem_ctx, trans.in.setup_count * sizeof(uint16));
if (!trans.in.setup) {
req_reply_error(req, NT_STATUS_NO_MEMORY);
return;
}
for (i=0;i<trans.in.setup_count;i++) {
trans.in.setup[i] = SVAL(req->in.vwv, VWV(19+i));
}
if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, &trans.in.params) ||
!req_pull_blob(req, req->in.hdr + data_ofs, data_count, &trans.in.data)) {
req_reply_error(req, NT_STATUS_FOOBAR);
return;
}
/* is it a partial request? if so, then send a 'send more' message */
if (param_total > param_count ||
data_total > data_count) {
DEBUG(0,("REWRITE: not handling partial nttrans requests!\n"));
return;
}
/* its a full request, give it to the backend */
status = nttrans_backend(req, &trans);
if (!NT_STATUS_IS_OK(status)) {
req_reply_error(req, status);
return;
}
params_left = trans.out.params.length;
data_left = trans.out.data.length;
params = trans.out.params.data;
data = trans.out.data.data;
req->control_flags |= REQ_CONTROL_PROTECTED;
/* we need to divide up the reply into chunks that fit into
the negotiated buffer size */
do {
uint16 this_data, this_param, max_bytes;
uint_t align1 = 1, align2 = (params_left ? 2 : 0);
req_setup_reply(req, 18 + trans.out.setup_count, 0);
max_bytes = req_max_data(req) - (align1 + align2);
this_param = params_left;
if (this_param > max_bytes) {
this_param = max_bytes;
}
max_bytes -= this_param;
this_data = data_left;
if (this_data > max_bytes) {
this_data = max_bytes;
}
req_grow_data(req, this_param + this_data + (align1 + align2));
SIVAL(req->out.vwv, 3, trans.out.params.length);
SIVAL(req->out.vwv, 7, trans.out.data.length);
SIVAL(req->out.vwv, 11, this_param);
SIVAL(req->out.vwv, 15, align1 + PTR_DIFF(req->out.data, req->out.hdr));
SIVAL(req->out.vwv, 19, PTR_DIFF(params, trans.out.params.data));
SIVAL(req->out.vwv, 23, this_data);
SIVAL(req->out.vwv, 27, align1 + align2 +
PTR_DIFF(req->out.data + this_param, req->out.hdr));
SIVAL(req->out.vwv, 31, PTR_DIFF(data, trans.out.data.data));
SCVAL(req->out.vwv, 35, trans.out.setup_count);
for (i=0;i<trans.out.setup_count;i++) {
SSVAL(req->out.vwv, VWV(18+i)+1, trans.out.setup[i]);
}
memset(req->out.data, 0, align1);
if (this_param != 0) {
memcpy(req->out.data + align1, params, this_param);
}
memset(req->out.data+this_param+align1, 0, align2);
if (this_data != 0) {
memcpy(req->out.data+this_param+align1+align2, data, this_data);
}
params_left -= this_param;
data_left -= this_data;
params += this_param;
data += this_data;
/* if this is the last chunk then the request can be destroyed */
if (params_left == 0 && data_left == 0) {
req->control_flags &= ~REQ_CONTROL_PROTECTED;
}
req_send_reply(req);
} while (params_left != 0 || data_left != 0);
}
/****************************************************************************
Reply to an SMBnttranss request
****************************************************************************/
void reply_nttranss(struct request_context *req)
{
req_reply_error(req, NT_STATUS_FOOBAR);
}

View File

@ -21,7 +21,9 @@
#include "includes.h"
#include "pthread.h"
#ifdef HAVE_BACKTRACE
#include "execinfo.h"
#endif
static void *connection_thread(void *thread_parm)
{
@ -267,12 +269,14 @@ static void thread_log_suspicious_usage(const char* from, const char* info)
char **bt_symbols;
DEBUG(1,("log_suspicious_usage: from %s info='%s'\n", from, info));
#ifdef HAVE_BACKTRACE
num_addresses = backtrace(addresses, 8);
bt_symbols = backtrace_symbols(addresses, num_addresses);
for (i=0; i<num_addresses; i++) {
DEBUG(1,("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]));
}
free(bt_symbols);
#endif
}
/*****************************************************************
@ -286,19 +290,29 @@ static void thread_print_suspicious_usage(const char* from, const char* info)
char **bt_symbols;
printf("log_suspicious_usage: from %s info='%s'\n", from, info);
#ifdef HAVE_BACKTRACE
num_addresses = backtrace(addresses, 8);
bt_symbols = backtrace_symbols(addresses, num_addresses);
for (i=0; i<num_addresses; i++) {
printf("log_suspicious_usage: %s%s\n", DEBUGTAB(1), bt_symbols[i]);
}
free(bt_symbols);
#endif
}
uint32 thread_get_task_id(void)
static uint32 thread_get_task_id(void)
{
return (uint32)pthread_self();
}
static void thread_log_task_id(int fd)
{
char *s;
asprintf(&s, "thread %u: ", (uint32)pthread_self());
write(fd, s, strlen(s));
free(s);
}
/****************************************************************************
catch serious errors
****************************************************************************/
@ -342,13 +356,14 @@ static void thread_fault_handler(int sig)
DEBUG(0,("INTERNAL ERROR: Signal %d in thread %lu (%s)\n",sig,(unsigned long int)pthread_self(),SAMBA_VERSION));
DEBUG(0,("Please read the file BUGS.txt in the distribution\n"));
DEBUG(0,("===============================================================\n"));
#ifdef HAVE_BACKTRACE
num_addresses = backtrace(addresses, 10);
bt_symbols = backtrace_symbols(addresses, num_addresses);
for (i=0; i<num_addresses; i++) {
DEBUG(9,("fault_report: %s\n", bt_symbols[i]));
}
free(bt_symbols);
#endif
pthread_exit(NULL); /* terminate failing thread only */
}
@ -384,6 +399,7 @@ static void model_startup(void)
d_ops.log_suspicious_usage = thread_log_suspicious_usage;
d_ops.print_suspicious_usage = thread_print_suspicious_usage;
d_ops.get_task_id = thread_get_task_id;
d_ops.log_task_id = thread_log_task_id;
register_debug_handlers("thread", &d_ops);
}

View File

@ -709,6 +709,7 @@ void reply_readbraw(struct request_context *req)
if (req->out.buffer == NULL) {
goto failed;
}
SIVAL(req->out.buffer, 0, 0); /* init NBT header */
/* tell the backend where to put the data */
io.readbraw.out.data = req->out.buffer + NBT_HDR_SIZE;
@ -723,11 +724,13 @@ void reply_readbraw(struct request_context *req)
req->out.size = io.readbraw.out.nread + NBT_HDR_SIZE;
req_send_reply(req);
return;
failed:
/* any failure in readbraw is equivalent to reading zero bytes */
req->out.size = 4;
req->out.buffer = talloc(req->mem_ctx, req->out.size);
SIVAL(req->out.buffer, 0, 0); /* init NBT header */
req_send_reply(req);
}
@ -742,6 +745,8 @@ static void reply_lockread_send(struct request_context *req)
CHECK_ASYNC_STATUS;
/* trim packet */
io->lockread.out.nread = MIN(io->lockread.out.nread,
req_max_data(req) - 3);
req_grow_data(req, 3 + io->lockread.out.nread);
/* construct reply */
@ -800,6 +805,8 @@ static void reply_read_send(struct request_context *req)
CHECK_ASYNC_STATUS;
/* trim packet */
io->read.out.nread = MIN(io->read.out.nread,
req_max_data(req) - 3);
req_grow_data(req, 3 + io->read.out.nread);
/* construct reply */
@ -833,7 +840,7 @@ void reply_read(struct request_context *req)
req_setup_reply(req, 5, 3 + io->read.in.count);
/* tell the backend where to put the data */
io->lockread.out.data = req->out.data + 3;
io->read.out.data = req->out.data + 3;
req->async.send_fn = reply_read_send;
req->async.private = io;
@ -856,6 +863,8 @@ static void reply_read_and_X_send(struct request_context *req)
CHECK_ASYNC_STATUS;
/* trim the packet to the right size */
io->readx.out.nread = MIN(io->readx.out.nread,
req_max_data(req) - 1);
req_grow_data(req, 1 + io->readx.out.nread);
/* construct reply */
@ -1922,26 +1931,6 @@ void reply_getattrE(struct request_context *req)
REQ_ASYNC_TAIL;
}
/****************************************************************************
Reply to a search.
Can be called from SMBsearch, SMBffirst or SMBfunique.
****************************************************************************/
void reply_search(struct request_context *req)
{
/* do this one later */
req_reply_error(req, NT_STATUS_FOOBAR);
}
/****************************************************************************
Reply to a fclose (stop directory search).
****************************************************************************/
void reply_fclose(struct request_context *req)
{
/* skip this one for now too */
req_reply_error(req, NT_STATUS_FOOBAR);
}
/****************************************************************************
reply to an old style session setup command
@ -2196,22 +2185,6 @@ void reply_transs2(struct request_context *req)
req_reply_error(req, NT_STATUS_FOOBAR);
}
/****************************************************************************
Reply to an SMBnttrans request
****************************************************************************/
void reply_nttrans(struct request_context *req)
{
req_reply_error(req, NT_STATUS_FOOBAR);
}
/****************************************************************************
Reply to an SMBnttranss request
****************************************************************************/
void reply_nttranss(struct request_context *req)
{
req_reply_error(req, NT_STATUS_FOOBAR);
}
/****************************************************************************
Reply to an SMBfindclose request

View File

@ -362,7 +362,34 @@ size_t req_push_str(struct request_context *req, char *dest, const char *str, in
return len;
}
/*
append raw bytes into the data portion of the request packet
return the number of bytes added
*/
size_t req_append_bytes(struct request_context *req,
const uint8 *bytes, size_t byte_len)
{
req_grow_allocation(req, byte_len + req->out.data_size);
memcpy(req->out.data + req->out.data_size, bytes, byte_len);
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 req_append_var_block(struct request_context *req,
const uint8 *bytes, uint16 byte_len)
{
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);
}
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

229
source4/smbd/search.c Normal file
View File

@ -0,0 +1,229 @@
/*
Unix SMB/CIFS implementation.
SMBsearch handling
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.
*/
/*
This file handles the parsing of transact2 requests
*/
#include "includes.h"
/* check req->async.status and if not OK then send an error reply */
#define CHECK_ASYNC_STATUS do { \
if (!NT_STATUS_IS_OK(req->async.status)) { \
req_reply_error(req, req->async.status); \
return; \
}} while (0)
/*
check if the backend wants to handle the request asynchronously.
if it wants it handled synchronously then call the send function
immediately
*/
#define REQ_ASYNC_TAIL do { \
if (!(req->control_flags & REQ_CONTROL_ASYNC)) { \
req->async.send_fn(req); \
}} while (0)
/* useful wrapper for talloc with NO_MEMORY reply */
#define REQ_TALLOC(ptr, size) do { \
ptr = talloc(req->mem_ctx, size); \
if (!ptr) { \
req_reply_error(req, NT_STATUS_NO_MEMORY); \
return; \
}} while (0)
#define CHECK_MIN_BLOB_SIZE(blob, size) do { \
if ((blob)->length < (size)) { \
return NT_STATUS_INFO_LENGTH_MISMATCH; \
}} while (0)
/* a structure to encapsulate the state information about
* an in-progress search first/next operation */
struct search_state {
struct request_context *req;
union smb_search_data *file;
uint16 last_entry_offset;
};
/*
fill a single entry in a search find reply
*/
static void find_fill_info(struct request_context *req,
union smb_search_data *file)
{
char *p = req->out.data + req->out.data_size;
uint32 dos_date;
char search_name[13];
DEBUG(9,("find_fill_info: input file data: attr=0x%x size=%u time=0x%x name=%13s\n",
file->search.attrib, file->search.size,
(uint32)file->search.write_time, file->search.name));
p += req_append_bytes(req, file->search.search_id.data, 21);
p += req_append_bytes(req, (char*)&file->search.attrib, 1);
put_dos_date((char*)&dos_date, 0, file->search.write_time);
p += req_append_bytes(req, (char*)&dos_date, 4);
p += req_append_bytes(req, (char*)&file->search.size, 4);
memset(&search_name[0], ' ', 13);
memcpy(&search_name[0], file->search.name,
MAX(13, strlen(file->search.name)));
p += req_append_bytes(req, &search_name[0], 13);
}
/* callback function for search first/next */
static BOOL find_callback(void *private, union smb_search_data *file)
{
struct search_state *state = (struct search_state *)private;
find_fill_info(state->req, file);
return True;
}
/****************************************************************************
Reply to a search.
****************************************************************************/
void reply_search(struct request_context *req)
{
union smb_search_first *sf;
union smb_search_next *sn;
DATA_BLOB resume_key;
uint16 resume_key_length;
struct search_state state;
char *p;
REQ_TALLOC(sf, sizeof(*sf));
/* parse request */
if (req->in.wct != 2) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
return;
}
p = req->in.data;
p += req_pull_ascii4(req, &sf->search_first.in.pattern,
p, STR_TERMINATE);
if (!sf->search_first.in.pattern) {
req_reply_error(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
return;
}
/* pull in type 5 byte and length */
if (!req_pull_blob(req, p, 3, &resume_key))
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
resume_key_length = SVAL(resume_key.data, 1);
p += 3;
DEBUG(19,("reply_search: pattern=%s, key_length=%d\n",
sf->search_first.in.pattern, resume_key_length));
/* setup state for callback */
state.req = req;
state.file = NULL;
state.last_entry_offset = 0;
/* construct reply */
req_setup_reply(req, 1, 0);
req_append_var_block(req, NULL, 0);
if (resume_key_length > 0) {
/* do a search next operation */
REQ_TALLOC(sn, sizeof(*sn));
sn->search_next.level = RAW_SEARCH_SEARCH;
req->async.private = sn;
if (!req_pull_blob(req, req->in.data, resume_key_length,
&(sn->search_next.in.search_id)))
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
sn->search_next.in.search_attrib = SVAL(req->in.vwv, VWV(1));
sn->search_next.in.max_count = SVAL(req->in.vwv, VWV(0));
/* call backend */
req->async.status = req->conn->ntvfs_ops->search_next(req,
sn, &state, find_callback);
SSVAL(req->out.vwv, VWV(0), sn->search_next.out.count);
} else {
/* do a search first operation */
req->async.private = sf;
sf->search_first.level = RAW_SEARCH_SEARCH;
sf->search_first.in.search_attrib = SVAL(req->in.vwv, VWV(1));
sf->search_first.in.max_count = SVAL(req->in.vwv, VWV(0));
/* call backend */
req->async.status = req->conn->ntvfs_ops->search_first(req,
sf, &state, find_callback);
SSVAL(req->out.vwv, VWV(0), sf->search_first.out.count);
}
req_send_reply(req);
}
/****************************************************************************
Reply to a fclose (async reply)
****************************************************************************/
static void reply_fclose_send(struct request_context *req)
{
CHECK_ASYNC_STATUS;
/* construct reply */
req_setup_reply(req, 1, 0);
req_send_reply(req);
}
/****************************************************************************
Reply to fclose (stop directory search).
****************************************************************************/
void reply_fclose(struct request_context *req)
{
union smb_search_next *sn;
DATA_BLOB resume_key;
uint16 resume_key_length;
REQ_TALLOC(sn, sizeof(*sn));
/* parse request */
if (req->in.wct != 2) {
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
return;
}
sn->search_next.level = RAW_SEARCH_FCLOSE;
/* pull in type 5 byte and length */
if (!req_pull_blob(req, req->in.data, 3, &resume_key))
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
resume_key_length = SVAL(resume_key.data, 1);
if (resume_key_length > 0) {
/* do a search close operation */
if (!req_pull_blob(req, req->in.data, resume_key_length,
&(sn->search_next.in.search_id)))
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
} else
req_reply_error(req, NT_STATUS_INVALID_PARAMETER);
req->async.send_fn = reply_fclose_send;
req->async.private = sn;
/* call backend */
req->async.status = req->conn->ntvfs_ops->search_next(req, sn,
NULL, NULL);
REQ_ASYNC_TAIL;
}