From 142d295aa8e70477c85d1835f2907f81c4c3c519 Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Mon, 18 Oct 2004 13:27:22 +0000 Subject: r3039: This solves the problem of async handlers in ntvfs backends not being in the right state when called. For example, when we use the unixuid handler in the chain of handlers, and a backend decides to continue a call asynchronously then we need to ensure that the continuation happens with the right security context. The solution is to add a new ntvfs operation ntvfs_async_setup(), which calls all the way down through the layers, setting up anything that is required, and takes a private pointer. The backend wanting to make a async calls can use ntvfs_async_setup() to ensure that the modules above it are called when doing async processing. (This used to be commit a256e71029727fa1659ade6257085df537308c7d) --- source4/ntvfs/cifs/vfs_cifs.c | 11 +++++++++++ source4/ntvfs/ipc/vfs_ipc.c | 11 +++++++++++ source4/ntvfs/nbench/vfs_nbench.c | 11 +++++++++++ source4/ntvfs/ntvfs.h | 6 +++++- source4/ntvfs/ntvfs_interface.c | 22 ++++++++++++++++++++++ source4/ntvfs/posix/pvfs_wait.c | 36 +++++++++++++++++++++++++++++++++--- source4/ntvfs/posix/vfs_posix.c | 1 + source4/ntvfs/simple/vfs_simple.c | 11 +++++++++++ source4/ntvfs/unixuid/vfs_unixuid.c | 15 +++++++++++++++ 9 files changed, 120 insertions(+), 4 deletions(-) (limited to 'source4/ntvfs') diff --git a/source4/ntvfs/cifs/vfs_cifs.c b/source4/ntvfs/cifs/vfs_cifs.c index 7c4a1d79d6..5b10e72411 100644 --- a/source4/ntvfs/cifs/vfs_cifs.c +++ b/source4/ntvfs/cifs/vfs_cifs.c @@ -563,6 +563,16 @@ static NTSTATUS cvfs_logoff(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } +/* + setup for an async call - nothing to do yet +*/ +static NTSTATUS cvfs_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + return NT_STATUS_OK; +} + /* lock a byte range */ @@ -748,6 +758,7 @@ NTSTATUS ntvfs_cifs_init(void) ops.search_close = cvfs_search_close; ops.trans = cvfs_trans; ops.logoff = cvfs_logoff; + ops.async_setup = cvfs_async_setup; if (lp_parm_bool(-1, "cifs", "maptrans2", False)) { ops.trans2 = cvfs_trans2; diff --git a/source4/ntvfs/ipc/vfs_ipc.c b/source4/ntvfs/ipc/vfs_ipc.c index 69fed6f86f..b37b3e917d 100644 --- a/source4/ntvfs/ipc/vfs_ipc.c +++ b/source4/ntvfs/ipc/vfs_ipc.c @@ -571,6 +571,16 @@ static NTSTATUS ipc_logoff(struct ntvfs_module_context *ntvfs, return NT_STATUS_OK; } +/* + setup for an async call +*/ +static NTSTATUS ipc_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + return NT_STATUS_OK; +} + /* lock a byte range */ @@ -795,6 +805,7 @@ NTSTATUS ntvfs_ipc_init(void) ops.search_close = ipc_search_close; ops.trans = ipc_trans; ops.logoff = ipc_logoff; + ops.async_setup = ipc_async_setup; /* register ourselves with the NTVFS subsystem. */ ret = register_backend("ntvfs", &ops); diff --git a/source4/ntvfs/nbench/vfs_nbench.c b/source4/ntvfs/nbench/vfs_nbench.c index 06c237afb5..6203c21506 100644 --- a/source4/ntvfs/nbench/vfs_nbench.c +++ b/source4/ntvfs/nbench/vfs_nbench.c @@ -489,6 +489,16 @@ static NTSTATUS nbench_logoff(struct ntvfs_module_context *ntvfs, return status; } +/* + async setup +*/ +static NTSTATUS nbench_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + return NT_STATUS_OK; +} + /* lock a byte range */ @@ -695,6 +705,7 @@ NTSTATUS ntvfs_nbench_init(void) ops.search_close = nbench_search_close; ops.trans = nbench_trans; ops.logoff = nbench_logoff; + ops.async_setup = nbench_async_setup; /* we don't register a trans2 handler as we want to be able to log individual trans2 requests */ diff --git a/source4/ntvfs/ntvfs.h b/source4/ntvfs/ntvfs.h index bee10e3c38..c9fe276f54 100644 --- a/source4/ntvfs/ntvfs.h +++ b/source4/ntvfs/ntvfs.h @@ -112,7 +112,11 @@ struct ntvfs_ops { /* logoff - called when a vuid is closed */ NTSTATUS (*logoff)(struct ntvfs_module_context *ntvfs, - struct smbsrv_request *req); + struct smbsrv_request *req); + + /* async_setup - called when a backend is processing a async request */ + NTSTATUS (*async_setup)(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, void *private); }; struct ntvfs_module_context { diff --git a/source4/ntvfs/ntvfs_interface.c b/source4/ntvfs/ntvfs_interface.c index 06cda11000..7ba1c0d6be 100644 --- a/source4/ntvfs/ntvfs_interface.c +++ b/source4/ntvfs/ntvfs_interface.c @@ -293,6 +293,17 @@ NTSTATUS ntvfs_logoff(struct smbsrv_request *req) return ntvfs->ops->logoff(ntvfs, req); } +/* async setup - called by a backend that wants to setup any state for + a async request */ +NTSTATUS ntvfs_async_setup(struct smbsrv_request *req, void *private) +{ + struct ntvfs_module_context *ntvfs = req->tcon->ntvfs_ctx->modules; + if (!ntvfs->ops->async_setup) { + return NT_STATUS_NOT_IMPLEMENTED; + } + return ntvfs->ops->async_setup(ntvfs, req, private); +} + /* initial setup */ NTSTATUS ntvfs_next_connect(struct ntvfs_module_context *ntvfs, struct smbsrv_request *req, const char *sharename) @@ -564,3 +575,14 @@ NTSTATUS ntvfs_next_logoff(struct ntvfs_module_context *ntvfs, } return ntvfs->next->ops->logoff(ntvfs->next, req); } + +/* async_setup - called when setting up for a async request */ +NTSTATUS ntvfs_next_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + if (!ntvfs->next || !ntvfs->next->ops->async_setup) { + return NT_STATUS_NOT_IMPLEMENTED; + } + return ntvfs->next->ops->async_setup(ntvfs->next, req, private); +} diff --git a/source4/ntvfs/posix/pvfs_wait.c b/source4/ntvfs/posix/pvfs_wait.c index 5815b8edde..2a4a1d286b 100644 --- a/source4/ntvfs/posix/pvfs_wait.c +++ b/source4/ntvfs/posix/pvfs_wait.c @@ -31,8 +31,22 @@ struct pvfs_wait { int msg_type; void *msg_ctx; struct event_context *ev; + struct smbsrv_request *req; + BOOL timed_out; }; +/* + called from the ntvfs layer when we have requested setup of an async + call. this ensures that async calls runs with the right state of + previous ntvfs handlers in the chain (such as security context) +*/ +NTSTATUS pvfs_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, void *private) +{ + struct pvfs_wait *pwait = private; + pwait->handler(pwait->private, pwait->timed_out); + return NT_STATUS_OK; +} /* receive a completion message for a wait @@ -41,6 +55,7 @@ static void pvfs_wait_dispatch(void *msg_ctx, void *private, uint32_t msg_type, servid_t src, DATA_BLOB *data) { struct pvfs_wait *pwait = private; + struct smbsrv_request *req; /* we need to check that this one is for us. This sender sends the private pointer as the body of the message. This might @@ -50,8 +65,16 @@ static void pvfs_wait_dispatch(void *msg_ctx, void *private, uint32_t msg_type, *(void **)data->data != pwait->private) { return; } - - pwait->handler(pwait->private, False); + pwait->timed_out = False; + req = pwait->req; + + /* the extra reference here is to ensure that the req + structure is not destroyed when the async request reply is + sent, which would cause problems with the other ntvfs + modules above us */ + talloc_increase_ref_count(req); + ntvfs_async_setup(pwait->req, pwait); + talloc_free(req); } @@ -61,7 +84,13 @@ static void pvfs_wait_dispatch(void *msg_ctx, void *private, uint32_t msg_type, static void pvfs_wait_timeout(struct event_context *ev, struct timed_event *te, time_t t) { struct pvfs_wait *pwait = te->private; - pwait->handler(pwait->private, True); + struct smbsrv_request *req = pwait->req; + + pwait->timed_out = True; + + talloc_increase_ref_count(req); + ntvfs_async_setup(pwait->req, pwait); + talloc_free(req); } @@ -103,6 +132,7 @@ void *pvfs_wait_message(struct pvfs_state *pvfs, pwait->msg_ctx = pvfs->tcon->smb_conn->connection->messaging_ctx; pwait->ev = req->tcon->smb_conn->connection->event.ctx; pwait->msg_type = msg_type; + pwait->req = req; /* setup a timer */ te.next_event = end_time; diff --git a/source4/ntvfs/posix/vfs_posix.c b/source4/ntvfs/posix/vfs_posix.c index 6e6c8b4275..e989f8de67 100644 --- a/source4/ntvfs/posix/vfs_posix.c +++ b/source4/ntvfs/posix/vfs_posix.c @@ -237,6 +237,7 @@ NTSTATUS ntvfs_posix_init(void) ops.search_close = pvfs_search_close; ops.trans = pvfs_trans; ops.logoff = pvfs_logoff; + ops.async_setup = pvfs_async_setup; /* register ourselves with the NTVFS subsystem. We register under the name 'default' as we wish to be the default diff --git a/source4/ntvfs/simple/vfs_simple.c b/source4/ntvfs/simple/vfs_simple.c index 7f5d447a09..7ebc040608 100644 --- a/source4/ntvfs/simple/vfs_simple.c +++ b/source4/ntvfs/simple/vfs_simple.c @@ -622,6 +622,16 @@ static NTSTATUS svfs_logoff(struct ntvfs_module_context *ntvfs, return NT_STATUS_NOT_SUPPORTED; } +/* + setup for an async call +*/ +static NTSTATUS svfs_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + return NT_STATUS_OK; +} + /* lock a byte range */ @@ -999,6 +1009,7 @@ NTSTATUS ntvfs_simple_init(void) ops.search_close = svfs_search_close; ops.trans = svfs_trans; ops.logoff = svfs_logoff; + ops.async_setup = svfs_async_setup; /* register ourselves with the NTVFS subsystem. We register under names 'simple' diff --git a/source4/ntvfs/unixuid/vfs_unixuid.c b/source4/ntvfs/unixuid/vfs_unixuid.c index 542b011c67..d0060bf11d 100644 --- a/source4/ntvfs/unixuid/vfs_unixuid.c +++ b/source4/ntvfs/unixuid/vfs_unixuid.c @@ -624,6 +624,20 @@ static NTSTATUS unixuid_logoff(struct ntvfs_module_context *ntvfs, return status; } +/* + async setup +*/ +static NTSTATUS unixuid_async_setup(struct ntvfs_module_context *ntvfs, + struct smbsrv_request *req, + void *private) +{ + NTSTATUS status; + + PASS_THRU_REQ(ntvfs, req, async_setup, (ntvfs, req, private)); + + return status; +} + /* lock a byte range */ @@ -767,6 +781,7 @@ NTSTATUS ntvfs_unixuid_init(void) ops.search_close = unixuid_search_close; ops.trans = unixuid_trans; ops.logoff = unixuid_logoff; + ops.async_setup = unixuid_async_setup; ops.name = "unixuid"; -- cgit