From 696fdc8cf91cc1660725fd93c2b91ec6b65d06b5 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 17 Nov 2004 12:36:14 +0000 Subject: r3806: added support to smb_server and pvfs for the NTTRANS Create call. This call has an optional sec_desc and ea_list. (This used to be commit 8379ad14e3d51a848a99865d9ce8d56a301e8a3c) --- source4/include/smb_interfaces.h | 10 ++- source4/libcli/raw/raweas.c | 2 +- source4/librpc/idl/xattr.idl | 2 + source4/ntvfs/posix/pvfs_open.c | 17 +++- source4/ntvfs/posix/pvfs_qfileinfo.c | 3 +- source4/ntvfs/posix/pvfs_setfileinfo.c | 6 +- source4/ntvfs/posix/pvfs_streams.c | 10 +++ source4/smb_server/nttrans.c | 137 ++++++++++++++++++++++++++++++--- source4/smb_server/reply.c | 2 + 9 files changed, 170 insertions(+), 19 deletions(-) diff --git a/source4/include/smb_interfaces.h b/source4/include/smb_interfaces.h index 43cb8af5a7..1f0912a149 100644 --- a/source4/include/smb_interfaces.h +++ b/source4/include/smb_interfaces.h @@ -433,7 +433,7 @@ union smb_fileinfo { enum smb_fileinfo_level level; union smb_fileinfo_in in; - struct smb_all_eas { + struct smb_ea_list { /* the ea_size is implied by the list */ uint_t num_eas; struct ea_struct *eas; @@ -1037,7 +1037,8 @@ enum smb_open_level { RAW_OPEN_OPEN, RAW_OPEN_OPENX, RAW_OPEN_MKNEW, RAW_OPEN_CREATE, RAW_OPEN_CTEMP, RAW_OPEN_SPLOPEN, - RAW_OPEN_NTCREATEX, RAW_OPEN_T2OPEN}; + RAW_OPEN_NTCREATEX, RAW_OPEN_T2OPEN, + RAW_OPEN_NTTRANS_CREATE}; /* the generic interface is defined to be equal to the NTCREATEX interface */ #define RAW_OPEN_GENERIC RAW_OPEN_NTCREATEX @@ -1063,6 +1064,11 @@ union smb_open { uint64_t file_id if create_options has the NTCREATEX_OPTIONS_OPEN_BY_FILE_ID flag set */ const char *fname; + + /* these last 2 elements are only used in the + NTTRANS varient of the call */ + struct security_descriptor *sec_desc; + struct smb_ea_list *ea_list; } in; struct { diff --git a/source4/libcli/raw/raweas.c b/source4/libcli/raw/raweas.c index da079c402b..52c7832a6c 100644 --- a/source4/libcli/raw/raweas.c +++ b/source4/libcli/raw/raweas.c @@ -122,7 +122,7 @@ NTSTATUS ea_pull_list(const DATA_BLOB *blob, *num_eas = 0; *eas = NULL; - while (ofs < ea_size) { + while (ofs+6 < ea_size) { uint_t len; DATA_BLOB blob2; diff --git a/source4/librpc/idl/xattr.idl b/source4/librpc/idl/xattr.idl index b2e13bfbe7..703fb2325b 100644 --- a/source4/librpc/idl/xattr.idl +++ b/source4/librpc/idl/xattr.idl @@ -59,6 +59,8 @@ interface xattr /* stream data is stored in attributes with the given prefix */ const string XATTR_DOSSTREAM_PREFIX = "user.DosStream."; + const int XATTR_MAX_STREAM_SIZE = 0x4000; + typedef struct { uint32 flags; uint64 size; diff --git a/source4/ntvfs/posix/pvfs_open.c b/source4/ntvfs/posix/pvfs_open.c index d8f3342f0d..1b9538d7e2 100644 --- a/source4/ntvfs/posix/pvfs_open.c +++ b/source4/ntvfs/posix/pvfs_open.c @@ -429,6 +429,20 @@ static NTSTATUS pvfs_create_file(struct pvfs_state *pvfs, return status; } + /* setup any EAs that were asked for */ + if (io->ntcreatex.in.ea_list) { + int i; + for (i=0;intcreatex.in.ea_list->num_eas;i++) { + status = pvfs_setfileinfo_ea_set(pvfs, name, fd, + &io->ntcreatex.in.ea_list->eas[i]); + if (!NT_STATUS_IS_OK(status)) { + idr_remove(pvfs->idtree_fnum, fnum); + close(fd); + return status; + } + } + } + /* form the lock context used for byte range locking and opendb locking */ status = pvfs_locking_key(name, f->handle, &f->handle->odb_locking_key); @@ -792,7 +806,8 @@ NTSTATUS pvfs_open(struct ntvfs_module_context *ntvfs, /* use the generic mapping code to avoid implementing all the different open calls. */ - if (io->generic.level != RAW_OPEN_GENERIC) { + if (io->generic.level != RAW_OPEN_GENERIC && + io->generic.level != RAW_OPEN_NTTRANS_CREATE) { return ntvfs_map_open(req, io, ntvfs); } diff --git a/source4/ntvfs/posix/pvfs_qfileinfo.c b/source4/ntvfs/posix/pvfs_qfileinfo.c index 3959fbfc16..f6e1288b1d 100644 --- a/source4/ntvfs/posix/pvfs_qfileinfo.c +++ b/source4/ntvfs/posix/pvfs_qfileinfo.c @@ -28,7 +28,8 @@ reply to a RAW_FILEINFO_ALL_EAS call */ static NTSTATUS pvfs_query_all_eas(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, - struct pvfs_filename *name, int fd, struct smb_all_eas *eas) + struct pvfs_filename *name, int fd, + struct smb_ea_list *eas) { NTSTATUS status; int i; diff --git a/source4/ntvfs/posix/pvfs_setfileinfo.c b/source4/ntvfs/posix/pvfs_setfileinfo.c index 37d8a290b8..d31bcac337 100644 --- a/source4/ntvfs/posix/pvfs_setfileinfo.c +++ b/source4/ntvfs/posix/pvfs_setfileinfo.c @@ -113,9 +113,9 @@ static NTSTATUS pvfs_setfileinfo_rename(struct pvfs_state *pvfs, /* add a single DOS EA */ -static NTSTATUS pvfs_setfileinfo_ea_set(struct pvfs_state *pvfs, - struct pvfs_filename *name, - int fd, struct ea_struct *ea) +NTSTATUS pvfs_setfileinfo_ea_set(struct pvfs_state *pvfs, + struct pvfs_filename *name, + int fd, struct ea_struct *ea) { struct xattr_DosEAs *ealist = talloc_p(pvfs, struct xattr_DosEAs); int i; diff --git a/source4/ntvfs/posix/pvfs_streams.c b/source4/ntvfs/posix/pvfs_streams.c index 13a4ca1265..12f783e172 100644 --- a/source4/ntvfs/posix/pvfs_streams.c +++ b/source4/ntvfs/posix/pvfs_streams.c @@ -271,6 +271,11 @@ ssize_t pvfs_stream_write(struct pvfs_state *pvfs, if (count == 0) { return 0; } + if (offset > XATTR_MAX_STREAM_SIZE) { + errno = ENOSPC; + return -1; + } + /* we have to load the existing stream, then modify, then save */ status = pvfs_xattr_load(pvfs, h, h->name->full_name, h->fd, XATTR_DOSSTREAM_PREFIX, h->name->stream_name, offset+count, &blob); @@ -320,6 +325,11 @@ NTSTATUS pvfs_stream_truncate(struct pvfs_state *pvfs, { NTSTATUS status; DATA_BLOB blob; + + if (length > XATTR_MAX_STREAM_SIZE) { + return NT_STATUS_DISK_FULL; + } + /* we have to load the existing stream, then modify, then save */ status = pvfs_xattr_load(pvfs, name, name->full_name, fd, XATTR_DOSSTREAM_PREFIX, name->stream_name, length, &blob); diff --git a/source4/smb_server/nttrans.c b/source4/smb_server/nttrans.c index 0ea92c80a0..b623578514 100644 --- a/source4/smb_server/nttrans.c +++ b/source4/smb_server/nttrans.c @@ -51,19 +51,141 @@ static void nttrans_setup_reply(struct smbsrv_request *req, /* parse NTTRANS_CREATE request */ static NTSTATUS nttrans_create(struct smbsrv_request *req, - struct smb_nttrans *trans) + struct smb_nttrans *trans) { - return NT_STATUS_FOOBAR; + union smb_open *io; + uint16_t fname_len; + uint32_t sd_length, ea_length; + NTSTATUS status; + uint8_t *params; + + if (trans->in.params.length < 54) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* parse the request */ + io = talloc_p(req, union smb_open); + if (io == NULL) { + return NT_STATUS_NO_MEMORY; + } + + io->ntcreatex.level = RAW_OPEN_NTTRANS_CREATE; + + params = trans->in.params.data; + + io->ntcreatex.in.flags = IVAL(params, 0); + io->ntcreatex.in.root_fid = IVAL(params, 4); + io->ntcreatex.in.access_mask = IVAL(params, 8); + io->ntcreatex.in.alloc_size = BVAL(params, 12); + io->ntcreatex.in.file_attr = IVAL(params, 20); + io->ntcreatex.in.share_access = IVAL(params, 24); + io->ntcreatex.in.open_disposition = IVAL(params, 28); + io->ntcreatex.in.create_options = IVAL(params, 32); + sd_length = IVAL(params, 36); + ea_length = IVAL(params, 40); + fname_len = IVAL(params, 44); + io->ntcreatex.in.impersonation = IVAL(params, 48); + io->ntcreatex.in.security_flags = CVAL(params, 52); + io->ntcreatex.in.sec_desc = NULL; + io->ntcreatex.in.ea_list = NULL; + + req_pull_string(req, &io->ntcreatex.in.fname, + params + 54, + trans->in.params.length - 54, + STR_NO_RANGE_CHECK | STR_TERMINATE); + if (!io->ntcreatex.in.fname) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (sd_length > trans->in.data.length || + ea_length > trans->in.data.length || + (sd_length+ea_length) > trans->in.data.length) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* this call has an optional security descriptor */ + if (sd_length != 0) { + DATA_BLOB blob; + blob.data = trans->in.data.data; + blob.length = sd_length; + io->ntcreatex.in.sec_desc = talloc_p(io, struct security_descriptor); + if (io->ntcreatex.in.sec_desc == NULL) { + return NT_STATUS_NO_MEMORY; + } + status = ndr_pull_struct_blob(&blob, io, + io->ntcreatex.in.sec_desc, + (ndr_pull_flags_fn_t)ndr_pull_security_descriptor); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + /* and an optional ea_list */ + if (ea_length > 4) { + DATA_BLOB blob; + blob.data = trans->in.data.data + sd_length; + blob.length = ea_length; + io->ntcreatex.in.ea_list = talloc_p(io, struct smb_ea_list); + if (io->ntcreatex.in.ea_list == NULL) { + return NT_STATUS_NO_MEMORY; + } + + /* w2k gets the length of the list wrong on the wire - auto-fix */ + SIVAL(blob.data, 0, ea_length); + + status = ea_pull_list(&blob, io, + &io->ntcreatex.in.ea_list->num_eas, + &io->ntcreatex.in.ea_list->eas); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + } + + /* call the backend - notice that we do it sync for now, until we support + async nttrans requests */ + status = ntvfs_openfile(req, io); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + trans->out.setup_count = 0; + trans->out.setup = NULL; + trans->out.params = data_blob_talloc(req, NULL, 69); + trans->out.data = data_blob(NULL, 0); + + params = trans->out.params.data; + if (params == NULL) { + return NT_STATUS_NO_MEMORY; + } + + SSVAL(params, 0, io->ntcreatex.out.oplock_level); + SSVAL(params, 2, io->ntcreatex.out.fnum); + SIVAL(params, 4, io->ntcreatex.out.create_action); + SIVAL(params, 8, 0); /* ea error offset */ + push_nttime(params, 12, io->ntcreatex.out.create_time); + push_nttime(params, 20, io->ntcreatex.out.access_time); + push_nttime(params, 28, io->ntcreatex.out.write_time); + push_nttime(params, 36, io->ntcreatex.out.change_time); + SIVAL(params, 44, io->ntcreatex.out.attrib); + SBVAL(params, 48, io->ntcreatex.out.alloc_size); + SBVAL(params, 56, io->ntcreatex.out.size); + SSVAL(params, 64, io->ntcreatex.out.file_type); + SSVAL(params, 66, io->ntcreatex.out.ipc_state); + SCVAL(params, 68, io->ntcreatex.out.is_directory); + + return NT_STATUS_OK; } /* parse NTTRANS_RENAME request */ static NTSTATUS nttrans_rename(struct smbsrv_request *req, - struct smb_nttrans *trans) + struct smb_nttrans *trans) { return NT_STATUS_FOOBAR; } -/* parse NTTRANS_IOCTL request + +/* + parse NTTRANS_IOCTL request */ static NTSTATUS nttrans_ioctl(struct smbsrv_request *req, struct smb_nttrans *trans) @@ -105,13 +227,6 @@ static NTSTATUS nttrans_ioctl(struct smbsrv_request *req, static NTSTATUS nttrans_backend(struct smbsrv_request *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: diff --git a/source4/smb_server/reply.c b/source4/smb_server/reply.c index 7b33f4334b..31616b9435 100644 --- a/source4/smb_server/reply.c +++ b/source4/smb_server/reply.c @@ -2294,6 +2294,8 @@ void reply_ntcreate_and_X(struct smbsrv_request *req) io->ntcreatex.in.create_options = IVAL(req->in.vwv, 39); io->ntcreatex.in.impersonation = IVAL(req->in.vwv, 43); io->ntcreatex.in.security_flags = CVAL(req->in.vwv, 47); + io->ntcreatex.in.ea_list = NULL; + io->ntcreatex.in.sec_desc = NULL; /* we need a neater way to handle this alignment */ if ((req->flags2 & FLAGS2_UNICODE_STRINGS) && -- cgit