diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/smb_server/smb2/fileio.c | 54 | ||||
-rw-r--r-- | source4/smb_server/smb2/smb2_server.h | 97 |
2 files changed, 150 insertions, 1 deletions
diff --git a/source4/smb_server/smb2/fileio.c b/source4/smb_server/smb2/fileio.c index b9f36fdc7a..778dd584ed 100644 --- a/source4/smb_server/smb2/fileio.c +++ b/source4/smb_server/smb2/fileio.c @@ -20,11 +20,63 @@ #include "includes.h" #include "libcli/smb2/smb2.h" +#include "libcli/smb2/smb2_calls.h" +#include "smb_server/smb_server.h" +#include "smb_server/service_smb_proto.h" #include "smb_server/smb2/smb2_server.h" +#include "ntvfs/ntvfs.h" + +static void smb2srv_create_send(struct ntvfs_request *ntvfs) +{ + struct smb2srv_request *req; + union smb_open *io; + + SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_open); + SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x58, True, io->smb2.out.blob.length)); + + SSVAL(req->out.body, 0x02, io->smb2.out.oplock_flags); + SIVAL(req->out.body, 0x04, io->smb2.out.create_action); + SBVAL(req->out.body, 0x08, io->smb2.out.create_time); + SBVAL(req->out.body, 0x10, io->smb2.out.access_time); + SBVAL(req->out.body, 0x18, io->smb2.out.write_time); + SBVAL(req->out.body, 0x20, io->smb2.out.change_time); + SBVAL(req->out.body, 0x28, io->smb2.out.alloc_size); + SBVAL(req->out.body, 0x30, io->smb2.out.size); + SIVAL(req->out.body, 0x38, io->smb2.out.file_attr); + SIVAL(req->out.body, 0x3C, io->smb2.out._pad); + smb2srv_push_handle(req->out.body, 0x40,io->smb2.out.file.ntvfs); + SMB2SRV_CHECK(smb2_push_o16s16_blob(&req->out, 0x50, io->smb2.out.blob)); + + smb2srv_send_reply(req); +} void smb2srv_create_recv(struct smb2srv_request *req) { - smb2srv_send_error(req, NT_STATUS_NOT_IMPLEMENTED); + union smb_open *io; + DATA_BLOB blob; + + SMB2SRV_CHECK_BODY_SIZE(req, 0x38, True); + SMB2SRV_TALLOC_IO_PTR(io, union smb_open); + SMB2SRV_SETUP_NTVFS_REQUEST(smb2srv_create_send, NTVFS_ASYNC_STATE_MAY_ASYNC); + + io->smb2.level = RAW_OPEN_SMB2; + io->smb2.in.oplock_flags = SVAL(req->in.body, 0x02); + io->smb2.in.impersonation = IVAL(req->in.body, 0x04); + io->smb2.in.unknown3[0] = IVAL(req->in.body, 0x08); + io->smb2.in.unknown3[1] = IVAL(req->in.body, 0x0C); + io->smb2.in.unknown3[2] = IVAL(req->in.body, 0x10); + io->smb2.in.unknown3[3] = IVAL(req->in.body, 0x14); + io->smb2.in.access_mask = IVAL(req->in.body, 0x18); + io->smb2.in.file_attr = IVAL(req->in.body, 0x1C); + io->smb2.in.share_access = IVAL(req->in.body, 0x20); + io->smb2.in.open_disposition = IVAL(req->in.body, 0x24); + io->smb2.in.create_options = IVAL(req->in.body, 0x28); + SMB2SRV_CHECK(smb2_pull_o16s16_string(&req->in, io, req->in.body+0x2C, &io->smb2.in.fname)); + SMB2SRV_CHECK(smb2_pull_o32s32_blob(&req->in, io, req->in.body+0x30, &blob)); + /* TODO: parse the blob */ + ZERO_STRUCT(io->smb2.in.eas); + + SMB2SRV_CALL_NTVFS_BACKEND(ntvfs_open(req->ntvfs, io)); } void smb2srv_close_recv(struct smb2srv_request *req) diff --git a/source4/smb_server/smb2/smb2_server.h b/source4/smb_server/smb2/smb2_server.h index 86b4f146be..6eea4e7e05 100644 --- a/source4/smb_server/smb2/smb2_server.h +++ b/source4/smb_server/smb2/smb2_server.h @@ -60,3 +60,100 @@ struct smb2srv_request { struct smbsrv_request; #include "smb_server/smb2/smb2_proto.h" + +/* useful way of catching wct errors with file and line number */ +#define SMB2SRV_CHECK_BODY_SIZE(req, size, dynamic) do { \ + size_t is_size = req->in.body_size; \ + uint16_t field_size = SVAL(req->in.body, 0); \ + uint16_t want_size = ((dynamic)?(size)+1:(size)); \ + if (is_size < (size)) { \ + DEBUG(0,("%s: buffer too small 0x%x. Expected 0x%x\n", \ + __location__, is_size, want_size)); \ + smb2srv_send_error(req, NT_STATUS_FOOBAR); \ + }\ + if (field_size != want_size) { \ + DEBUG(0,("%s: unexpected fixed body size 0x%x. Expected 0x%x\n", \ + __location__, field_size, want_size)); \ + smb2srv_send_error(req, NT_STATUS_FOOBAR); \ + } \ +} while (0) + +#define SMB2SRV_CHECK(cmd) do {\ + NTSTATUS _status; \ + _status = cmd; \ + if (!NT_STATUS_IS_OK(_status)) { \ + smb2srv_send_error(req, _status); \ + return; \ + } \ +} while (0) + +/* useful wrapper for talloc with NO_MEMORY reply */ +#define SMB2SRV_TALLOC_IO_PTR(ptr, type) do { \ + ptr = talloc(req, type); \ + if (!ptr) { \ + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); \ + return; \ + } \ + req->io_ptr = ptr; \ +} while (0) + +#define SMB2SRV_SETUP_NTVFS_REQUEST(send_fn, state) do { \ + req->ntvfs = ntvfs_request_create(req->tcon->ntvfs, req, \ + req->session->session_info,\ + 0, \ + 0, \ + req->request_time, \ + req, send_fn, state); \ + if (!req->ntvfs) { \ + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); \ + return; \ + } \ + if (!talloc_reference(req->ntvfs, req)) { \ + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); \ + return; \ + } \ + req->ntvfs->frontend_data.private_data = req; \ +} while (0) + +#define SMB2SRV_CHECK_FILE_HANDLE(handle) do { \ + if (!handle) { \ + smb2srv_send_error(req, NT_STATUS_INVALID_HANDLE); \ + 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 SMB2SRV_CALL_NTVFS_BACKEND(cmd) do { \ + req->ntvfs->async_states->status = cmd; \ + if (!(req->ntvfs->async_states->state & NTVFS_ASYNC_STATE_ASYNC)) { \ + req->ntvfs->async_states->send_fn(req->ntvfs); \ + } \ +} while (0) + +/* check req->ntvfs->async_states->status and if not OK then send an error reply */ +#define SMB2SRV_CHECK_ASYNC_STATUS_ERR_SIMPLE do { \ + req = talloc_get_type(ntvfs->async_states->private_data, struct smb2srv_request); \ + if (NT_STATUS_IS_ERR(ntvfs->async_states->status)) { \ + smb2srv_send_error(req, ntvfs->async_states->status); \ + return; \ + } \ +} while (0) +#define SMB2SRV_CHECK_ASYNC_STATUS_ERR(ptr, type) do { \ + SMB2SRV_CHECK_ASYNC_STATUS_ERR_SIMPLE; \ + ptr = talloc_get_type(req->io_ptr, type); \ +} while (0) +#define SMB2SRV_CHECK_ASYNC_STATUS_SIMPLE do { \ + req = talloc_get_type(ntvfs->async_states->private_data, struct smb2srv_request); \ + if (!NT_STATUS_IS_OK(ntvfs->async_states->status)) { \ + smb2srv_send_error(req, ntvfs->async_states->status); \ + return; \ + } \ +} while (0) +#define SMB2SRV_CHECK_ASYNC_STATUS(ptr, type) do { \ + SMB2SRV_CHECK_ASYNC_STATUS_SIMPLE; \ + ptr = talloc_get_type(req->io_ptr, type); \ +} while (0) |