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
+ 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,
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.
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
This file handles the parsing of transact2 requests
*/
#include "includes.h"
-#include "dlinklist.h"
#include "smb_server/smb_server.h"
-#include "librpc/gen_ndr/ndr_misc.h"
#include "ntvfs/ntvfs.h"
#include "libcli/raw/libcliraw.h"
+#include "libcli/raw/raw_proto.h"
#define TRANS2_CHECK_ASYNC_STATUS_SIMPLE do { \
if (!NT_STATUS_IS_OK(req->ntvfs->async_states->status)) { \
/* 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,
- uint16_t setup_count)
+ uint8_t setup_count)
{
trans->out.setup_count = setup_count;
if (setup_count > 0) {
io->t2open.in.num_eas = 0;
io->t2open.in.eas = NULL;
- smbsrv_blob_pull_string(req, &trans->in.params, 28, &io->t2open.in.fname, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 28, &io->t2open.in.fname, 0);
if (io->t2open.in.fname == NULL) {
return NT_STATUS_FOOBAR;
}
NT_STATUS_HAVE_NO_MEMORY(io);
io->t2mkdir.level = RAW_MKDIR_T2MKDIR;
- smbsrv_blob_pull_string(req, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 4, &io->t2mkdir.in.path, 0);
if (io->t2mkdir.in.path == NULL) {
return NT_STATUS_FOOBAR;
}
level = SVAL(trans->in.params.data, 0);
- smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
if (st->generic.in.file.path == NULL) {
return NT_STATUS_FOOBAR;
}
case RAW_SFILEINFO_UNIX_BASIC:
case RAW_SFILEINFO_UNIX_LINK:
case RAW_SFILEINFO_UNIX_HLINK:
- case RAW_SFILEINFO_1023:
+ case RAW_SFILEINFO_PIPE_INFORMATION:
+ case RAW_SFILEINFO_VALID_DATA_INFORMATION:
+ case RAW_SFILEINFO_SHORT_NAME_INFORMATION:
case RAW_SFILEINFO_1025:
+ case RAW_SFILEINFO_1027:
case RAW_SFILEINFO_1029:
+ case RAW_SFILEINFO_1030:
+ case RAW_SFILEINFO_1031:
case RAW_SFILEINFO_1032:
- case RAW_SFILEINFO_1039:
- case RAW_SFILEINFO_1040:
+ case RAW_SFILEINFO_1036:
+ case RAW_SFILEINFO_1041:
+ case RAW_SFILEINFO_1042:
+ case RAW_SFILEINFO_1043:
+ case RAW_SFILEINFO_1044:
+ return NT_STATUS_INVALID_LEVEL;
+
+ default:
+ /* we need a default here to cope with invalid values on the wire */
return NT_STATUS_INVALID_LEVEL;
}
return smbsrv_pull_passthru_sfileinfo(st, passthru_level, st,
blob, SMBSRV_REQ_DEFAULT_STR_FLAGS(req),
- req);
+ &req->in.bufinfo);
}
/*
level = SVAL(trans->in.params.data, 0);
- smbsrv_blob_pull_string(req, &trans->in.params, 6, &st->generic.in.file.path, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 6, &st->generic.in.file.path, 0);
if (st->generic.in.file.path == NULL) {
return NT_STATUS_FOOBAR;
}
struct find_state {
struct trans_op *op;
void *search;
- enum smb_search_level level;
+ enum smb_search_data_level data_level;
uint16_t last_entry_offset;
uint16_t flags;
};
fill a single entry in a trans2 find reply
*/
static NTSTATUS find_fill_info(struct find_state *state,
- union smb_search_data *file)
+ const union smb_search_data *file)
{
struct smbsrv_request *req = state->op->req;
struct smb_trans2 *trans = state->op->trans;
uint8_t *data;
- uint_t ofs = trans->out.data.length;
+ unsigned int ofs = trans->out.data.length;
uint32_t ea_size;
- switch (state->level) {
- case RAW_SEARCH_SEARCH:
- case RAW_SEARCH_FFIRST:
- case RAW_SEARCH_FUNIQUE:
- case RAW_SEARCH_GENERIC:
- case RAW_SEARCH_SMB2:
+ switch (state->data_level) {
+ case RAW_SEARCH_DATA_GENERIC:
+ case RAW_SEARCH_DATA_SEARCH:
/* handled elsewhere */
return NT_STATUS_INVALID_LEVEL;
- case RAW_SEARCH_STANDARD:
+ case RAW_SEARCH_DATA_STANDARD:
if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27));
SIVAL(trans->out.data.data, ofs, file->standard.resume_key);
STR_LEN8BIT | STR_TERMINATE | STR_LEN_NOTERM));
break;
- case RAW_SEARCH_EA_SIZE:
+ case RAW_SEARCH_DATA_EA_SIZE:
if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 31));
SIVAL(trans->out.data.data, ofs, file->ea_size.resume_key);
TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
break;
- case RAW_SEARCH_EA_LIST:
+ case RAW_SEARCH_DATA_EA_LIST:
ea_size = ea_list_size(file->ea_list.eas.num_eas, file->ea_list.eas.eas);
if (state->flags & FLAG_TRANS2_FIND_REQUIRE_RESUME) {
TRANS2_CHECK(smbsrv_blob_grow_data(trans, &trans->out.data, ofs + 27 + ea_size));
TRANS2_CHECK(smbsrv_blob_fill_data(trans, &trans->out.data, trans->out.data.length + 1));
break;
- case RAW_SEARCH_DIRECTORY_INFO:
- case RAW_SEARCH_FULL_DIRECTORY_INFO:
- case RAW_SEARCH_NAME_INFO:
- case RAW_SEARCH_BOTH_DIRECTORY_INFO:
- case RAW_SEARCH_ID_FULL_DIRECTORY_INFO:
- case RAW_SEARCH_ID_BOTH_DIRECTORY_INFO:
- return smbsrv_push_passthru_search(trans, &trans->out.data, state->level, file,
+ 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:
+ return smbsrv_push_passthru_search(trans, &trans->out.data, state->data_level, file,
SMBSRV_REQ_DEFAULT_STR_FLAGS(req));
+
+ case RAW_SEARCH_DATA_UNIX_INFO:
+ case RAW_SEARCH_DATA_UNIX_INFO2:
+ return NT_STATUS_INVALID_LEVEL;
}
return NT_STATUS_OK;
}
/* callback function for trans2 findfirst/findnext */
-static BOOL find_callback(void *private, union smb_search_data *file)
+static bool find_callback(void *private_data, const union smb_search_data *file)
{
- struct find_state *state = talloc_get_type(private, struct find_state);
+ struct find_state *state = talloc_get_type(private_data, struct find_state);
struct smb_trans2 *trans = state->op->trans;
- uint_t old_length;
+ unsigned int old_length;
old_length = trans->out.data.length;
trans->out.data.length > trans->in.max_data) {
/* restore the old length and tell the backend to stop */
smbsrv_blob_grow_data(trans, &trans->out.data, old_length);
- return False;
+ return false;
}
state->last_entry_offset = old_length;
- return True;
+ return true;
}
/*
level = SVAL(trans->in.params.data, 6);
search->t2ffirst.in.storage_type = IVAL(trans->in.params.data, 8);
- smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2ffirst.in.pattern, 0);
if (search->t2ffirst.in.pattern == NULL) {
return NT_STATUS_FOOBAR;
}
- search->t2ffirst.level = (enum smb_search_level)level;
- if (search->t2ffirst.level >= RAW_SEARCH_GENERIC) {
+ search->t2ffirst.level = RAW_SEARCH_TRANS2;
+ search->t2ffirst.data_level = (enum smb_search_data_level)level;
+ if (search->t2ffirst.data_level >= RAW_SEARCH_DATA_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
- if (search->t2ffirst.level == RAW_SEARCH_EA_LIST) {
+ if (search->t2ffirst.data_level == RAW_SEARCH_DATA_EA_LIST) {
TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
&search->t2ffirst.in.num_names,
&search->t2ffirst.in.ea_names));
NT_STATUS_HAVE_NO_MEMORY(state);
state->op = op;
state->search = search;
- state->level = search->t2ffirst.level;
+ state->data_level = search->t2ffirst.data_level;
state->last_entry_offset= 0;
state->flags = search->t2ffirst.in.flags;
search->t2fnext.in.resume_key = IVAL(trans->in.params.data, 6);
search->t2fnext.in.flags = SVAL(trans->in.params.data, 10);
- smbsrv_blob_pull_string(req, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
+ smbsrv_blob_pull_string(&req->in.bufinfo, &trans->in.params, 12, &search->t2fnext.in.last_name, 0);
if (search->t2fnext.in.last_name == NULL) {
return NT_STATUS_FOOBAR;
}
- search->t2fnext.level = (enum smb_search_level)level;
- if (search->t2fnext.level >= RAW_SEARCH_GENERIC) {
+ search->t2fnext.level = RAW_SEARCH_TRANS2;
+ search->t2fnext.data_level = (enum smb_search_data_level)level;
+ if (search->t2fnext.data_level >= RAW_SEARCH_DATA_GENERIC) {
return NT_STATUS_INVALID_LEVEL;
}
- if (search->t2fnext.level == RAW_SEARCH_EA_LIST) {
+ if (search->t2fnext.data_level == RAW_SEARCH_DATA_EA_LIST) {
TRANS2_CHECK(ea_pull_name_list(&trans->in.data, req,
&search->t2fnext.in.num_names,
&search->t2fnext.in.ea_names));
NT_STATUS_HAVE_NO_MEMORY(state);
state->op = op;
state->search = search;
- state->level = search->t2fnext.level;
+ state->data_level = search->t2fnext.data_level;
state->last_entry_offset= 0;
state->flags = search->t2fnext.in.flags;
return NT_STATUS_FOOBAR;
}
+int smbsrv_trans_partial_destructor(struct smbsrv_trans_partial *tp)
+{
+ DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
+ return 0;
+}
+
/*
send a continue request
static void reply_trans_continue(struct smbsrv_request *req, uint8_t command,
struct smb_trans2 *trans)
{
+ struct smbsrv_request *req2;
struct smbsrv_trans_partial *tp;
int count;
tp = talloc(req, struct smbsrv_trans_partial);
- tp->req = talloc_reference(tp, req);
- tp->trans = trans;
+ tp->req = req;
+ tp->u.trans = trans;
tp->command = command;
DLIST_ADD(req->smb_conn->trans_partial, tp);
+ talloc_set_destructor(tp, smbsrv_trans_partial_destructor);
+
+ req2 = smbsrv_setup_secondary_request(req);
/* send a 'please continue' reply */
- smbsrv_setup_reply(req, 0, 0);
- smbsrv_send_reply(req);
+ smbsrv_setup_reply(req2, 0, 0);
+ smbsrv_send_reply(req2);
}
the negotiated buffer size */
do {
uint16_t this_data, this_param, max_bytes;
- uint_t align1 = 1, align2 = (params_left ? 2 : 0);
+ unsigned int align1 = 1, align2 = (params_left ? 2 : 0);
struct smbsrv_request *this_req;
max_bytes = req_max_data(req) - (align1 + align2);
PTR_DIFF(this_req->out.data + this_param, this_req->out.hdr));
SSVAL(this_req->out.vwv, VWV(8), PTR_DIFF(data, trans->out.data.data));
- SSVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
+ SCVAL(this_req->out.vwv, VWV(9), trans->out.setup_count);
+ SCVAL(this_req->out.vwv, VWV(9)+1, 0); /* reserved */
for (i=0;i<trans->out.setup_count;i++) {
SSVAL(this_req->out.vwv, VWV(10+i), trans->out.setup[i]);
}
}
if (command == SMBtrans) {
- req_pull_string(req, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
+ req_pull_string(&req->in.bufinfo, &trans->in.trans_name, req->in.data, -1, STR_TERMINATE);
}
- 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)) {
+ if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, &trans->in.params) ||
+ !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &trans->in.data)) {
smbsrv_send_error(req, NT_STATUS_FOOBAR);
return;
}
uint16_t param_disp, data_disp;
uint16_t param_total, data_total;
DATA_BLOB params, data;
+ uint8_t wct;
+
+ if (command == SMBtrans2) {
+ wct = 9;
+ } else {
+ wct = 8;
+ }
/* parse request */
- if (req->in.wct < 8) {
+ if (req->in.wct != wct) {
+ /*
+ * TODO: add some error code tests
+ * w2k3 returns NT_STATUS_DOS(ERRSRV, ERRerror) here
+ */
smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
return;
}
return;
}
- trans = tp->trans;
+ trans = tp->u.trans;
param_total = SVAL(req->in.vwv, VWV(0));
data_total = SVAL(req->in.vwv, VWV(1));
data_ofs = SVAL(req->in.vwv, VWV(6));
data_disp = SVAL(req->in.vwv, VWV(7));
- if (!req_pull_blob(req, req->in.hdr + param_ofs, param_count, ¶ms) ||
- !req_pull_blob(req, req->in.hdr + data_ofs, data_count, &data)) {
+ if (!req_pull_blob(&req->in.bufinfo, req->in.hdr + param_ofs, param_count, ¶ms) ||
+ !req_pull_blob(&req->in.bufinfo, req->in.hdr + data_ofs, data_count, &data)) {
smbsrv_send_error(req, NT_STATUS_INVALID_PARAMETER);
return;
}
uint8_t,
param_disp + param_count);
if (trans->in.params.data == NULL) {
- goto failed;
+ smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
+ return;
}
trans->in.params.length = param_disp + param_count;
}
uint8_t,
data_disp + data_count);
if (trans->in.data.data == NULL) {
- goto failed;
+ smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
+ return;
}
trans->in.data.length = data_disp + data_count;
}
if (trans->in.params.length == param_total &&
trans->in.data.length == data_total) {
/* its now complete */
- DLIST_REMOVE(tp->req->smb_conn->trans_partial, tp);
- reply_trans_complete(tp->req, command, trans);
+ req = tp->req;
+ talloc_free(tp);
+ reply_trans_complete(req, command, trans);
}
return;
-
-failed:
- smbsrv_send_error(tp->req, NT_STATUS_NO_MEMORY);
- DLIST_REMOVE(req->smb_conn->trans_partial, tp);
- talloc_free(req);
- talloc_free(tp);
}