From: Andrew Tridgell Date: Wed, 28 May 2008 06:28:37 +0000 (+1000) Subject: implement the documented SMB2 create blobs in the server X-Git-Tag: samba-4.0.0alpha4~19^2~7 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=9fc70e2ed6a54f6d9a0530f4d37c0f8acadb6778;p=thirdparty%2Fsamba.git implement the documented SMB2 create blobs in the server Not all of them are honoured yet, but they are all parsed and the ones that have SMB equivalents are honoured --- diff --git a/source/ntvfs/ipc/vfs_ipc.c b/source/ntvfs/ipc/vfs_ipc.c index ea7b54ae6ac..8ac7ac7d034 100644 --- a/source/ntvfs/ipc/vfs_ipc.c +++ b/source/ntvfs/ipc/vfs_ipc.c @@ -321,6 +321,7 @@ static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs, status = ipc_open_generic(ntvfs, req, oi->smb2.in.fname, &p); NT_STATUS_NOT_OK_RETURN(status); + ZERO_STRUCT(oi->smb2.out); oi->smb2.out.file.ntvfs = p->handle; oi->smb2.out.oplock_level = oi->smb2.in.oplock_level; oi->smb2.out.create_action = NTCREATEX_ACTION_EXISTED; @@ -332,7 +333,6 @@ static NTSTATUS ipc_open_smb2(struct ntvfs_module_context *ntvfs, oi->smb2.out.size = 0; oi->smb2.out.file_attr = FILE_ATTRIBUTE_NORMAL; oi->smb2.out.reserved2 = 0; - oi->smb2.out.blob = data_blob(NULL, 0); return status; } diff --git a/source/ntvfs/ntvfs_generic.c b/source/ntvfs/ntvfs_generic.c index 06d89a717be..9227295696b 100644 --- a/source/ntvfs/ntvfs_generic.c +++ b/source/ntvfs/ntvfs_generic.c @@ -207,6 +207,7 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs, break; case RAW_OPEN_SMB2: + ZERO_STRUCT(io->smb2.out); io->smb2.out.file.ntvfs = io2->generic.out.file.ntvfs; switch (io2->generic.out.oplock_level) { case BATCH_OPLOCK_RETURN: @@ -232,7 +233,6 @@ static NTSTATUS ntvfs_map_open_finish(struct ntvfs_module_context *ntvfs, io->smb2.out.size = io2->generic.out.size; io->smb2.out.file_attr = io2->generic.out.attrib; io->smb2.out.reserved2 = 0; - io->smb2.out.blob = data_blob(NULL, 0); break; default: @@ -512,7 +512,7 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs, } io2->generic.in.root_fid = 0; io2->generic.in.access_mask = io->smb2.in.desired_access; - io2->generic.in.alloc_size = 0; + io2->generic.in.alloc_size = io->smb2.in.alloc_size; io2->generic.in.file_attr = io->smb2.in.file_attributes; io2->generic.in.share_access = io->smb2.in.share_access; io2->generic.in.open_disposition= io->smb2.in.create_disposition; @@ -520,8 +520,14 @@ NTSTATUS ntvfs_map_open(struct ntvfs_module_context *ntvfs, io2->generic.in.impersonation = io->smb2.in.impersonation_level; io2->generic.in.security_flags = 0; io2->generic.in.fname = io->smb2.in.fname; - io2->generic.in.sec_desc = NULL; - io2->generic.in.ea_list = NULL; + io2->generic.in.sec_desc = io->smb2.in.sec_desc; + io2->generic.in.ea_list = &io->smb2.in.eas; + + /* we don't support timewarp yet */ + if (io->smb2.in.timewarp != 0) { + status = NT_STATUS_OBJECT_NAME_NOT_FOUND; + break; + } /* we need to check these bits before we check the private mask */ if (io2->generic.in.create_options & NTCREATEX_OPTIONS_NOT_SUPPORTED_MASK) { diff --git a/source/ntvfs/posix/pvfs_open.c b/source/ntvfs/posix/pvfs_open.c index 49710806c7e..0f08136a79b 100644 --- a/source/ntvfs/posix/pvfs_open.c +++ b/source/ntvfs/posix/pvfs_open.c @@ -634,6 +634,8 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, return status; } + /* support initial alloc sizes */ + name->dos.alloc_size = io->ntcreatex.in.alloc_size; name->dos.attrib = attrib; status = pvfs_dosattrib_save(pvfs, name, fd); if (!NT_STATUS_IS_OK(status)) { @@ -1464,6 +1466,7 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, talloc_free(lck); return pvfs_map_errno(pvfs, errno); } + name->dos.alloc_size = io->ntcreatex.in.alloc_size; name->dos.attrib = attrib; status = pvfs_dosattrib_save(pvfs, name, fd); if (!NT_STATUS_IS_OK(status)) { diff --git a/source/smb_server/smb2/fileio.c b/source/smb_server/smb2/fileio.c index 5ab217bbfd6..086ddc690eb 100644 --- a/source/smb_server/smb2/fileio.c +++ b/source/smb_server/smb2/fileio.c @@ -25,14 +25,19 @@ #include "smb_server/smb2/smb2_server.h" #include "ntvfs/ntvfs.h" #include "param/param.h" +#include "libcli/raw/libcliraw.h" +#include "libcli/raw/raw_proto.h" +#include "librpc/gen_ndr/ndr_security.h" static void smb2srv_create_send(struct ntvfs_request *ntvfs) { struct smb2srv_request *req; union smb_open *io; + DATA_BLOB blob; SMB2SRV_CHECK_ASYNC_STATUS(io, union smb_open); - SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x58, true, io->smb2.out.blob.length)); + SMB2SRV_CHECK(smb2_create_blob_push(req, &blob, io->smb2.out.blobs)); + SMB2SRV_CHECK(smb2srv_setup_reply(req, 0x58, true, blob.length)); SCVAL(req->out.body, 0x02, io->smb2.out.oplock_level); SCVAL(req->out.body, 0x03, io->smb2.out.reserved); @@ -46,7 +51,7 @@ static void smb2srv_create_send(struct ntvfs_request *ntvfs) SIVAL(req->out.body, 0x38, io->smb2.out.file_attr); SIVAL(req->out.body, 0x3C, io->smb2.out.reserved2); smb2srv_push_handle(req->out.body, 0x40, io->smb2.out.file.ntvfs); - SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x50, io->smb2.out.blob)); + SMB2SRV_CHECK(smb2_push_o32s32_blob(&req->out, 0x50, blob)); /* also setup the chained file handle */ req->chained_file_handle = req->_chained_file_handle; @@ -59,11 +64,13 @@ void smb2srv_create_recv(struct smb2srv_request *req) { union smb_open *io; DATA_BLOB blob; + int i; 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); + ZERO_STRUCT(io->smb2.in); io->smb2.level = RAW_OPEN_SMB2; io->smb2.in.security_flags = CVAL(req->in.body, 0x02); io->smb2.in.oplock_level = CVAL(req->in.body, 0x03); @@ -77,10 +84,67 @@ void smb2srv_create_recv(struct smb2srv_request *req) 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); - ZERO_STRUCT(io->smb2.in.blobs); - + SMB2SRV_CHECK(smb2_create_blob_parse(io, blob, &io->smb2.in.blobs)); + + /* interpret the parsed tags that a server needs to respond to */ + for (i=0;ismb2.in.blobs.num_blobs;i++) { + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_EXTA) == 0) { + SMB2SRV_CHECK(ea_pull_list_chained(&io->smb2.in.blobs.blobs[i].data, io, + &io->smb2.in.eas.num_eas, + &io->smb2.in.eas.eas)); + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_SECD) == 0) { + enum ndr_err_code ndr_err; + io->smb2.in.sec_desc = talloc(io, struct security_descriptor); + if (io->smb2.in.sec_desc == NULL) { + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); + return; + } + ndr_err = ndr_pull_struct_blob(&io->smb2.in.blobs.blobs[i].data, io, NULL, + io->smb2.in.sec_desc, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + smb2srv_send_error(req, ndr_map_error2ntstatus(ndr_err)); + return; + } + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNQ) == 0) { + io->smb2.in.durable_open = true; + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_DHNC) == 0) { + if (io->smb2.in.blobs.blobs[i].data.length != 16) { + smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + io->smb2.in.durable_handle = talloc(io, struct smb2_handle); + if (io->smb2.in.durable_handle == NULL) { + smb2srv_send_error(req, NT_STATUS_NO_MEMORY); + return; + } + smb2_pull_handle(io->smb2.in.blobs.blobs[i].data.data, io->smb2.in.durable_handle); + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_ALSI) == 0) { + if (io->smb2.in.blobs.blobs[i].data.length != 8) { + smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + io->smb2.in.alloc_size = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) { + io->smb2.in.query_maximal_access = true; + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_TWRP) == 0) { + if (io->smb2.in.blobs.blobs[i].data.length != 8) { + smb2srv_send_error(req, NT_STATUS_INVALID_PARAMETER); + return; + } + io->smb2.in.timewarp = BVAL(io->smb2.in.blobs.blobs[i].data.data, 0); + } + if (strcmp(io->smb2.in.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) { + io->smb2.in.query_on_disk_id = true; + } + } + /* the VFS backend does not yet handle NULL filenames */ if (io->smb2.in.fname == NULL) { io->smb2.in.fname = "";