mirror of
https://github.com/samba-team/samba.git
synced 2024-12-23 17:34:34 +03:00
parent
2e5ae6f065
commit
42c6a2548a
@ -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 \
|
||||
|
@ -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.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;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
273
source4/smbd/nttrans.c
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
229
source4/smbd/search.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user