📄 trans2.c
字号:
/* Unix SMB/CIFS implementation. transaction2 handling 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 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 "lib/util/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)) { \ 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, uint16_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 NTSTATUS trans2_qfsinfo(struct smbsrv_request *req, struct trans_op *op){ struct smb_trans2 *trans = op->trans; union smb_fsinfo *fsinfo; uint16_t level; /* make sure we got enough parameters */ if (trans->in.params.length != 2) { return NT_STATUS_FOOBAR; } fsinfo = talloc(op, union smb_fsinfo); NT_STATUS_HAVE_NO_MEMORY(fsinfo); level = SVAL(trans->in.params.data, 0); /* work out the backend level - we make it 1-1 in the header */ fsinfo->generic.level = (enum smb_fsinfo_level)level; if (fsinfo->generic.level >= RAW_QFS_GENERIC) { return NT_STATUS_INVALID_LEVEL; } op->op_info = fsinfo; op->send_fn = trans2_qfsinfo_send; return ntvfs_fsinfo(req->ntvfs, fsinfo);}/* trans2 open implementation send*/static NTSTATUS trans2_open_send(struct trans_op *op){ struct smbsrv_request *req = op->req; struct smb_trans2 *trans = op->trans; union smb_open *io; TRANS2_CHECK_ASYNC_STATUS(io, union smb_open); TRANS2_CHECK(trans2_setup_reply(trans, 30, 0, 0)); smbsrv_push_fnum(trans->out.params.data, VWV(0), io->t2open.out.file.ntvfs); SSVAL(trans->out.params.data, VWV(1), io->t2open.out.attrib); srv_push_dos_date3(req->smb_conn, trans->out.params.data, VWV(2), io->t2open.out.write_time); SIVAL(trans->out.params.data, VWV(4), io->t2open.out.size); SSVAL(trans->out.params.data, VWV(6), io->t2open.out.access); SSVAL(trans->out.params.data, VWV(7), io->t2open.out.ftype); SSVAL(trans->out.params.data, VWV(8), io->t2open.out.devstate); SSVAL(trans->out.params.data, VWV(9), io->t2open.out.action); SIVAL(trans->out.params.data, VWV(10), 0); /* reserved */ SSVAL(trans->out.params.data, VWV(12), 0); /* EaErrorOffset */ SIVAL(trans->out.params.data, VWV(13), 0); /* EaLength */ return NT_STATUS_OK;}/* trans2 open implementation*/static NTSTATUS trans2_open(struct smbsrv_request *req, struct trans_op *op){ struct smb_trans2 *trans = op->trans; union smb_open *io; /* make sure we got enough parameters */ if (trans->in.params.length < 29) { return NT_STATUS_FOOBAR; } io = talloc(op, union smb_open); NT_STATUS_HAVE_NO_MEMORY(io); io->t2open.level = RAW_OPEN_T2OPEN; io->t2open.in.flags = SVAL(trans->in.params.data, VWV(0)); io->t2open.in.open_mode = SVAL(trans->in.params.data, VWV(1)); io->t2open.in.search_attrs = SVAL(trans->in.params.data, VWV(2)); io->t2open.in.file_attrs = SVAL(trans->in.params.data, VWV(3)); io->t2open.in.write_time = srv_pull_dos_date(req->smb_conn, trans->in.params.data + VWV(4)); io->t2open.in.open_func = SVAL(trans->in.params.data, VWV(6)); io->t2open.in.size = IVAL(trans->in.params.data, VWV(7)); io->t2open.in.timeout = IVAL(trans->in.params.data, VWV(9)); io->t2open.in.num_eas = 0; io->t2open.in.eas = NULL; 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; } TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2open.in.num_eas, &io->t2open.in.eas)); op->op_info = io; op->send_fn = trans2_open_send; return ntvfs_open(req->ntvfs, io);}/* trans2 simple send*/static NTSTATUS trans2_simple_send(struct trans_op *op){ struct smbsrv_request *req = op->req; struct smb_trans2 *trans = op->trans; TRANS2_CHECK_ASYNC_STATUS_SIMPLE; TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0)); SSVAL(trans->out.params.data, VWV(0), 0); return NT_STATUS_OK;}/* trans2 mkdir implementation*/static NTSTATUS trans2_mkdir(struct smbsrv_request *req, struct trans_op *op){ struct smb_trans2 *trans = op->trans; union smb_mkdir *io; /* make sure we got enough parameters */ if (trans->in.params.length < 5) { return NT_STATUS_FOOBAR; } io = talloc(op, union smb_mkdir); NT_STATUS_HAVE_NO_MEMORY(io); io->t2mkdir.level = RAW_MKDIR_T2MKDIR; 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; } TRANS2_CHECK(ea_pull_list(&trans->in.data, io, &io->t2mkdir.in.num_eas, &io->t2mkdir.in.eas)); op->op_info = io; op->send_fn = trans2_simple_send; return ntvfs_mkdir(req->ntvfs, io);}static NTSTATUS trans2_push_fileinfo(struct smbsrv_connection *smb_conn, TALLOC_CTX *mem_ctx, DATA_BLOB *blob, union smb_fileinfo *st, int default_str_flags){ uint32_t list_size; enum smb_fileinfo_level passthru_level; switch (st->generic.level) { case RAW_FILEINFO_GENERIC: case RAW_FILEINFO_GETATTR: case RAW_FILEINFO_GETATTRE: case RAW_FILEINFO_SEC_DESC: case RAW_FILEINFO_SMB2_ALL_EAS: case RAW_FILEINFO_SMB2_ALL_INFORMATION: /* handled elsewhere */ return NT_STATUS_INVALID_LEVEL; case RAW_FILEINFO_UNIX_BASIC: case RAW_FILEINFO_UNIX_LINK: /* not implemented yet */ return NT_STATUS_INVALID_LEVEL; case RAW_FILEINFO_STANDARD: TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 22)); srv_push_dos_date2(smb_conn, blob->data, 0, st->standard.out.create_time); srv_push_dos_date2(smb_conn, blob->data, 4, st->standard.out.access_time); srv_push_dos_date2(smb_conn, blob->data, 8, st->standard.out.write_time); SIVAL(blob->data, 12, st->standard.out.size); SIVAL(blob->data, 16, st->standard.out.alloc_size); SSVAL(blob->data, 20, st->standard.out.attrib); return NT_STATUS_OK; case RAW_FILEINFO_EA_SIZE: TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, 26)); srv_push_dos_date2(smb_conn, blob->data, 0, st->ea_size.out.create_time); srv_push_dos_date2(smb_conn, blob->data, 4, st->ea_size.out.access_time); srv_push_dos_date2(smb_conn, blob->data, 8, st->ea_size.out.write_time); SIVAL(blob->data, 12, st->ea_size.out.size); SIVAL(blob->data, 16, st->ea_size.out.alloc_size); SSVAL(blob->data, 20, st->ea_size.out.attrib); SIVAL(blob->data, 22, st->ea_size.out.ea_size); return NT_STATUS_OK; case RAW_FILEINFO_EA_LIST: list_size = ea_list_size(st->ea_list.out.num_eas, st->ea_list.out.eas); TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size)); ea_put_list(blob->data, st->ea_list.out.num_eas, st->ea_list.out.eas); return NT_STATUS_OK; case RAW_FILEINFO_ALL_EAS: list_size = ea_list_size(st->all_eas.out.num_eas, st->all_eas.out.eas); TRANS2_CHECK(smbsrv_blob_grow_data(mem_ctx, blob, list_size)); ea_put_list(blob->data, st->all_eas.out.num_eas, st->all_eas.out.eas); return NT_STATUS_OK; case RAW_FILEINFO_IS_NAME_VALID: return NT_STATUS_OK; case RAW_FILEINFO_BASIC_INFO: passthru_level = RAW_FILEINFO_BASIC_INFORMATION; break; case RAW_FILEINFO_STANDARD_INFO: passthru_level = RAW_FILEINFO_STANDARD_INFORMATION; break; case RAW_FILEINFO_EA_INFO: passthru_level = RAW_FILEINFO_EA_INFORMATION; break; case RAW_FILEINFO_COMPRESSION_INFO: passthru_level = RAW_FILEINFO_COMPRESSION_INFORMATION; break; case RAW_FILEINFO_ALL_INFO: passthru_level = RAW_FILEINFO_ALL_INFORMATION; break; case RAW_FILEINFO_NAME_INFO: passthru_level = RAW_FILEINFO_NAME_INFORMATION; break; case RAW_FILEINFO_ALT_NAME_INFO: passthru_level = RAW_FILEINFO_ALT_NAME_INFORMATION; break; case RAW_FILEINFO_STREAM_INFO: passthru_level = RAW_FILEINFO_STREAM_INFORMATION; break; default: passthru_level = st->generic.level; break; } return smbsrv_push_passthru_fileinfo(mem_ctx, blob, passthru_level, st, default_str_flags);}/* fill in the reply from a qpathinfo or qfileinfo call*/static NTSTATUS trans2_fileinfo_send(struct trans_op *op){ struct smbsrv_request *req = op->req; struct smb_trans2 *trans = op->trans; union smb_fileinfo *st; TRANS2_CHECK_ASYNC_STATUS(st, union smb_fileinfo); TRANS2_CHECK(trans2_setup_reply(trans, 2, 0, 0)); SSVAL(trans->out.params.data, 0, 0); TRANS2_CHECK(trans2_push_fileinfo(req->smb_conn, trans, &trans->out.data, st, SMBSRV_REQ_DEFAULT_STR_FLAGS(req))); return NT_STATUS_OK;}/* trans2 qpathinfo implementation*/static NTSTATUS trans2_qpathinfo(struct smbsrv_request *req, struct trans_op *op){ struct smb_trans2 *trans = op->trans; union smb_fileinfo *st; uint16_t level; /* make sure we got enough parameters */ if (trans->in.params.length < 2) { return NT_STATUS_FOOBAR; } st = talloc(op, union smb_fileinfo); NT_STATUS_HAVE_NO_MEMORY(st); level = SVAL(trans->in.params.data, 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -