The Samba-Bugzilla – Attachment 9761 Details for
Bug 10344
SessionLogoff on a signed connection with an outstanding notify request crashes smbd.
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Replacement fix after metze gave it a going-over :-).
async-logoff1-master.micro.patchset (text/plain), 57.76 KB, created by
Jeremy Allison
on 2014-03-08 01:04:43 UTC
(
hide
)
Description:
Replacement fix after metze gave it a going-over :-).
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2014-03-08 01:04:43 UTC
Size:
57.76 KB
patch
obsolete
>From 786324d44fb8e797d53db7904d231f2012fcfd57 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 5 Mar 2014 14:07:11 -0800 >Subject: [PATCH 01/26] s3: smbd: SMB2 server. Add a generic wait_queue > mechanism. > >NTSTATUS smbd_smb2_wait_for_request_to_complete( > struct smbd_smb2_request *smb2req_to_awaken, > struct smbd_smb2_request *smb2req_to_wait_for, > struct tevent_context *ev, > void (*callback_fn)(struct tevent_req *), > void *priv_ptr) > > Parameters are: > > struct smbd_smb2_request *smb2req_to_awaken - SMB2 request to be awoken. > struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. > struct tevent_context *ev - Event context. > void (*callback_fn)(struct tevent_req *) - Callback Function to call > once request has completed. > void *priv_ptr - Private pointer passed to > callback. > >Allows an SMB2 request to suspend itself via registering a >wait request using tevent_wait_send() on another SMB2 request. > >The suspending request will be awoken only when the >second SMB2 request completes and sends its reply >back to the client. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/globals.h | 38 ++++++++++++++++ > source3/smbd/smb2_server.c | 105 +++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 143 insertions(+) > >diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h >index 3baa048..a352ad8 100644 >--- a/source3/smbd/globals.h >+++ b/source3/smbd/globals.h >@@ -254,6 +254,27 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req); > size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req); > void remove_smb2_chained_fsp(files_struct *fsp); > >+/************************************************************* >+ Add a tevent request to the wait queue associated with an >+ SMB2 request. Will get notified once the SMB2 request completes. >+ >+ Parameters are: >+ >+ struct smbd_smb2_request *smb2req_to_awaken, - SMB2 request to be awoken. >+ struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. >+ struct tevent_context *ev, - Event context. >+ void (*callback_fn)(struct tevent_req *), - Callback Function to call >+ once request has completed. >+ void *priv_ptr - Private pointer passed to >+ callback. >+*************************************************************/ >+ >+NTSTATUS smbd_smb2_wait_for_request_to_complete( >+ struct smbd_smb2_request *smb2req_to_awaken, >+ struct smbd_smb2_request *smb2req_to_wait_for, >+ struct tevent_context *ev, >+ void (*callback_fn)(struct tevent_req *), >+ void *priv_ptr); > NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req, > uint32_t data_length); > >@@ -480,6 +501,16 @@ struct smbd_smb2_send_queue { > TALLOC_CTX *mem_ctx; > }; > >+struct smb2_request_wait_list { >+ struct smb2_request_wait_list *prev, *next; >+ /* >+ * Waiting event to trigger once the enclosing >+ * struct smbd_smb2_request has sent out a reply. >+ * This pointer is created by tevent_wait_send(). >+ */ >+ struct tevent_req *wait_req; >+}; >+ > struct smbd_smb2_request { > struct smbd_smb2_request *prev, *next; > >@@ -487,6 +518,13 @@ struct smbd_smb2_request { > > struct smbd_smb2_send_queue queue_entry; > >+ /* >+ * A list of wait events that represent >+ * other SMB2 requests waiting for this >+ * request to complete. >+ */ >+ struct smb2_request_wait_list *wait_list; >+ > /* the session the request operates on, maybe NULL */ > struct smbXsrv_session *session; > uint64_t last_session_id; >diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c >index 3c46efd..3ef0964 100644 >--- a/source3/smbd/smb2_server.c >+++ b/source3/smbd/smb2_server.c >@@ -29,6 +29,7 @@ > #include "../lib/util/bitmap.h" > #include "../librpc/gen_ndr/krb5pac.h" > #include "auth.h" >+#include "lib/tevent_wait.h" > > static void smbd_smb2_connection_handler(struct tevent_context *ev, > struct tevent_fd *fde, >@@ -1161,6 +1162,13 @@ static struct smbd_smb2_request *dup_smb2_req(const struct smbd_smb2_request *re > newreq->do_signing = req->do_signing; > newreq->current_idx = req->current_idx; > >+ /* >+ * Note we never duplicate the wait list of >+ * SMB2 requests to awaken. The wait list >+ * is associated with the SMB2 request left >+ * on the request queue. >+ */ >+ > outvec = talloc_zero_array(newreq, struct iovec, count); > if (!outvec) { > TALLOC_FREE(newreq); >@@ -1606,6 +1614,99 @@ static void smbd_smb2_request_pending_timer(struct tevent_context *ev, > } > } > >+/************************************************************* >+ Destructor for a wait list entry. >+ Ensures we are removed from any linked list >+ associated with an SMB2 request we may still be on. >+ Only matters if the request to be awoken finishes >+ before the request doing the wake-up. >+*************************************************************/ >+ >+static int smbd_smb2_cleanup_wait_list_entry(struct smb2_request_wait_list *pwe) >+{ >+ if (pwe->prev) { >+ /* >+ * This is only the case when the SMB2 request to >+ * be awakened has finished and is being freed before >+ * the SMB2 request that should awaken us. This should >+ * be a very rare occurrence. >+ */ >+ struct smb2_request_wait_list *wl_head; >+ DLIST_HEAD(pwe, wl_head); >+ DLIST_REMOVE(wl_head, pwe); >+ } >+ return 0; >+} >+ >+/************************************************************* >+ Add a tevent request to the wait queue associated with an >+ SMB2 request. Will get notified once the SMB2 request completes. >+ >+ Parameters are: >+ >+ struct smbd_smb2_request *smb2req_to_awaken, - SMB2 request to be awoken. >+ struct smbd_smb2_request *smb2req_to_wait_for - SMB2 request to wait for. >+ struct tevent_context *ev, - Event context. >+ void (*callback_fn)(struct tevent_req *), - Callback Function to call >+ once request has completed. >+ void *priv_ptr - Private pointer passed to >+ callback. >+*************************************************************/ >+ >+NTSTATUS smbd_smb2_wait_for_request_to_complete( >+ struct smbd_smb2_request *smb2req_to_awaken, >+ struct smbd_smb2_request *smb2req_to_wait_for, >+ struct tevent_context *ev, >+ void (*callback_fn)(struct tevent_req *), >+ void *priv_ptr) >+{ >+ struct smb2_request_wait_list *pwe = talloc_zero(smb2req_to_awaken, >+ struct smb2_request_wait_list); >+ if (pwe == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ >+ pwe->wait_req = tevent_wait_send(pwe, ev); >+ if (pwe->wait_req == NULL) { >+ TALLOC_FREE(pwe); >+ return NT_STATUS_NO_MEMORY; >+ } >+ tevent_req_set_callback(pwe->wait_req, >+ callback_fn, >+ priv_ptr); >+ DLIST_ADD_END(smb2req_to_wait_for->wait_list, pwe, >+ struct smb2_request_wait_list *); >+ >+ /* >+ * The following is needed in case the SMB2 request >+ * to_awaken finishes and is deleted before the >+ * request we want to awaken us. >+ */ >+ talloc_set_destructor(pwe, smbd_smb2_cleanup_wait_list_entry); >+ return NT_STATUS_OK; >+} >+ >+/************************************************************* >+ Awaken all tevent requests that were waiting for this >+ SMB2 request to complete. >+*************************************************************/ >+ >+static void smbd_smb2_awaken_waiting_requests(struct smbd_smb2_request *req) >+{ >+ struct smb2_request_wait_list *pwl_next; >+ struct smb2_request_wait_list *pwl; >+ >+ for (pwl = req->wait_list; pwl; pwl = pwl_next) { >+ pwl_next = pwl->next; >+ >+ tevent_wait_done(pwl->wait_req); >+ >+ DLIST_REMOVE(req->wait_list, pwl); >+ /* Esnure the destructor is safe. */ >+ pwl->next = pwl->prev = NULL; >+ } >+} >+ > static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) > { > struct smbd_server_connection *sconn = req->sconn; >@@ -1627,6 +1728,8 @@ static NTSTATUS smbd_smb2_request_process_cancel(struct smbd_smb2_request *req) > * cancel requests never have a response > */ > DLIST_REMOVE(req->sconn->smb2.requests, req); >+ /* Wake all other requests waiting for completion. */ >+ smbd_smb2_awaken_waiting_requests(req); > TALLOC_FREE(req); > > for (cur = sconn->smb2.requests; cur; cur = cur->next) { >@@ -2483,6 +2586,8 @@ static NTSTATUS smbd_smb2_request_reply(struct smbd_smb2_request *req) > * move it off the "being processed" queue. > */ > DLIST_REMOVE(req->sconn->smb2.requests, req); >+ /* Wake all other requests waiting for completion. */ >+ smbd_smb2_awaken_waiting_requests(req); > > req->queue_entry.mem_ctx = req; > req->queue_entry.vector = req->out.vector; >-- >1.9.0.279.gdc9e3eb > > >From a84a4528047210b1780090ba186d6b4dfd17d2f6 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 13 Jan 2014 14:12:18 -0800 >Subject: [PATCH 02/26] s3: SMB2 logoff - factor code out into a function > remove_outstanding_session_refs(). > >We will be reusing this. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 38 ++++++++++++++++++++++---------------- > 1 file changed, 22 insertions(+), 16 deletions(-) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 9d7193b..16cc5cd 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -455,10 +455,30 @@ static int pp_self_ref_destructor(struct smbd_smb2_session_setup_state **pp_stat > return 0; > } > >-static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) >+static void remove_outstanding_session_refs(struct smbd_smb2_request *smb2req) > { > struct smbd_smb2_request *preq; > >+ for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >+ if (preq == smb2req) { >+ /* Don't remove the session from the current >+ request in flight. */ >+ continue; >+ } >+ if (preq->session == smb2req->session) { >+ preq->session = NULL; >+ /* >+ * If we no longer have a session we can't >+ * sign or encrypt replies. >+ */ >+ preq->do_signing = false; >+ preq->do_encryption = false; >+ } >+ } >+} >+ >+static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_setup_state *state) >+{ > /* > * If state->session is not NULL, > * we move the session from the session table to the request on failure >@@ -479,21 +499,7 @@ static int smbd_smb2_session_setup_state_destructor(struct smbd_smb2_session_set > * to it. > */ > >- for (preq = state->smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >- if (preq == state->smb2req) { >- continue; >- } >- if (preq->session == state->smb2req->session) { >- preq->session = NULL; >- /* >- * If we no longer have a session we can't >- * sign or encrypt replies. >- */ >- preq->do_signing = false; >- preq->do_encryption = false; >- } >- } >- >+ remove_outstanding_session_refs(state->smb2req); > return 0; > } > >-- >1.9.0.279.gdc9e3eb > > >From c19bcf46932a92511bc1638ed4eaecd50381f71a Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 13 Jan 2014 14:31:31 -0800 >Subject: [PATCH 03/26] s3: SMB2 logoff - add > find_outstanding_session_request() > >Walk the outstanding SMB2 requests and return the >first one (not including the current request being processed) >on this session. Return NULL if there are no outstanding >requests on this session. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 43 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 16cc5cd..91565f0 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -794,6 +794,49 @@ static NTSTATUS smbd_smb2_session_setup_recv(struct tevent_req *req, > return status; > } > >+/******************************************************** >+ Walk the outstanding SMB2 requests and return the >+ first one (not including the current request being processed) >+ on this session. Return NULL if there are no outstanding >+ requests on this session. >+********************************************************/ >+ >+static struct smbd_smb2_request *find_outstanding_session_request( >+ const struct smbd_smb2_request *smb2req) >+{ >+ struct smbd_smb2_request *preq; >+ >+ if (smb2req->session == NULL) { >+ return NULL; >+ } >+ for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >+ if (preq == smb2req) { >+ /* Can't cancel current request. */ >+ continue; >+ } >+ if (preq->session != smb2req->session) { >+ /* Request on different session. */ >+ continue; >+ } >+ >+ if (preq->compound_related) { >+ /* >+ * Never cancel anything in a compound >+ * request. Way too hard to deal with >+ * the result. >+ */ >+ continue; >+ } >+ >+ /* >+ * If we get here we've found a request >+ * request we're going to cancel. >+ */ >+ break; >+ } >+ return preq; >+} >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From 9935124d0f047afe8bd6928bf20974d30f8d0a0a Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:03:22 -0800 >Subject: [PATCH 04/26] s3: smbd: SMB2 logoff - Add definition of struct > smbd_smb2_logout_state. > >Not yet used - will be used in async logoff code. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 91565f0..93f6936 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -837,6 +837,11 @@ static struct smbd_smb2_request *find_outstanding_session_request( > return preq; > } > >+struct smbd_smb2_logout_state { >+ struct smbd_smb2_request *smb2req; >+ struct tevent_context *ev; >+}; >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From 62e5ea1e98f94d0b843bc9ee850f58f4179f0cba Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:04:59 -0800 >Subject: [PATCH 05/26] s3: smbd: SMB2 logoff - Add tevent_wait.h header to > smb2_sesssetup.c > >Will be used in async logoff code. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 93f6936..a995224 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -28,6 +28,7 @@ > #include "../lib/tsocket/tsocket.h" > #include "../libcli/security/security.h" > #include "../lib/util/tevent_ntstatus.h" >+#include "lib/tevent_wait.h" > > static struct tevent_req *smbd_smb2_session_setup_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, >-- >1.9.0.279.gdc9e3eb > > >From a0c95e5a232f7f269f7e9f07d14ea47c9f2819cd Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:11:33 -0800 >Subject: [PATCH 06/26] smbd: SMB2 logoff - Add utility function > wait_for_outstanding_requests(). > >This looks for an outstanding request on this session, >calls tevent_req_cancel() on it and then uses the new >SMB2 request wait mechanism smbd_smb2_wait_for_request_to_complete() >to add a tevent request to the wait queue associated >with the SMB2 request we just cancelled. > >Returns NT_STATUS_RETRY if we are waiting. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 47 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 47 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index a995224..8684dba 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -843,6 +843,53 @@ struct smbd_smb2_logout_state { > struct tevent_context *ev; > }; > >+static void smbd_smb2_logoff_do(struct tevent_req *subreq); >+ >+/*************************************************************** >+ Utility function to wait for outstanding SMB2 requests on >+ this session. >+ If we return NT_STATUS_RETRY we have set ourselves to wait >+ for another request to complete. >+***************************************************************/ >+ >+static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_logout_state *state, >+ struct tevent_req *req) >+{ >+ struct smbd_smb2_request *smb2req = state->smb2req; >+ struct smbd_smb2_request *smb2_wait_req; >+ NTSTATUS status; >+ >+ /* >+ * Try and find a request to cancel. If we can, >+ * cancel it and tell ourselves to wait unti it's finished. >+ */ >+ smb2_wait_req = find_outstanding_session_request(smb2req); >+ if (smb2_wait_req != NULL) { >+ >+ tevent_req_cancel(smb2_wait_req->subreq); >+ >+ status = smbd_smb2_wait_for_request_to_complete( >+ smb2req, /* Request to wake up on completion. */ >+ smb2_wait_req, /* Request we're waiting on. */ >+ state->ev, /* Event context. */ >+ smbd_smb2_logoff_do, /* callback. */ >+ req); /* Private pointer. */ >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(0, ("logoff wait failed: %s\n", >+ nt_errstr(status))); >+ return status; >+ } >+ /* We're waiting on another SMB2 request. */ >+ return NT_STATUS_RETRY; >+ } >+ >+ return NT_STATUS_OK; >+} >+ >+static void smbd_smb2_logoff_do(struct tevent_req *subreq) >+{ >+} >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From 6eec70b595aebf8be83cf9c64a127f0f1ee08277 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:15:07 -0800 >Subject: [PATCH 07/26] smbd: SMB2 logoff - Add utility function > try_to_tear_down_session(). > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 28 ++++++++++++++++++++++++++++ > 1 file changed, 28 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 8684dba..08862a0 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -886,6 +886,34 @@ static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_logout_state *sta > return NT_STATUS_OK; > } > >+/*************************************************************** >+ Utility function to do the work of tearing down a session. >+***************************************************************/ >+ >+static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) >+{ >+ NTSTATUS status = smbXsrv_session_logoff(smb2req->session); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ /* >+ * We may need to sign the response, so we need to keep >+ * the session until the response is sent to the wire. >+ */ >+ talloc_steal(smb2req, smb2req->session); >+ /* >+ * The return from smbXsrv_session_logoff() >+ * leaves all outstanding pointers to >+ * smb2req->session not on this request in an >+ * undefined state, ensure we don't try and >+ * access any req->session pointers once >+ * we return. >+ */ >+ remove_outstanding_session_refs(smb2req); >+ return NT_STATUS_OK; >+} >+ > static void smbd_smb2_logoff_do(struct tevent_req *subreq) > { > } >-- >1.9.0.279.gdc9e3eb > > >From 50a36a8c01e93eee75c4632ee5e4c5459c4544c8 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:33:00 -0800 >Subject: [PATCH 08/26] s3: smbd: SMB2 logoff - Add wait completion function > smbd_smb2_logoff_do(). > >Wait callback function called when we were woken up by an >SMB2 request we were waiting on completing. Checks to see >if we should still wait, and goes back to sleep if so, >otherwise tears down the session and finishes the request. > >When re-awoken calls change_to_root_user() as SMB2_OP_LOGOFF >has .as_root = true in smb2_server.c and we have processed >other commands so may have swiched user whilst we were >waiting. Thanks to Metze for pointing this out. > >This avoids any tevent reentrancy and is a clean, simple way >of handling deferred notification. Many thanks to Volker >for showing the way to do this inside smb2_close.c. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 63 ++++++++++++++++++++++++++++++++++++++++--- > 1 file changed, 59 insertions(+), 4 deletions(-) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 08862a0..b5fd873 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -914,10 +914,6 @@ static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) > return NT_STATUS_OK; > } > >-static void smbd_smb2_logoff_do(struct tevent_req *subreq) >-{ >-} >- > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >@@ -959,3 +955,62 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > > return smbd_smb2_request_done(req, outbody, NULL); > } >+ >+/*************************************************************** >+ Wait callback function called when we were woken up by an >+ SMB2 request we were waiting on completing. Checks to see >+ if we should still wait, and goes back to sleep if so, >+ otherwise tears down the session and finishes the request. >+***************************************************************/ >+ >+static void smbd_smb2_logoff_do(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct smbd_smb2_logout_state *state = tevent_req_data( >+ req, struct smbd_smb2_logout_state); >+ NTSTATUS status; >+ int ret; >+ >+ ret = tevent_wait_recv(subreq); >+ TALLOC_FREE(subreq); >+ if (ret != 0) { >+ DEBUG(10, ("tevent_wait_recv returned %s\n", >+ strerror(ret))); >+ /* >+ * Continue anyway, this should never happen >+ */ >+ } >+ >+ /* Should we still wait ? */ >+ status = wait_for_outstanding_requests(state, req); >+ >+ if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { >+ /* >+ * NT_STATUS_RETRY means we're waiting >+ * for another cancelled request to complete. >+ */ >+ return; >+ } >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("waiting for requetsts failed: %s\n", >+ nt_errstr(status))); >+ tevent_req_done(req); >+ return; >+ } >+ >+ /* >+ * As we've been awoken, we may have changed >+ * uid in the meantime. Ensure we're still >+ * root (SMB2_OP_LOGOFF has .as_root = true). >+ */ >+ change_to_root_user(); >+ >+ status = try_to_tear_down_session(state->smb2req); >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("tearing down session failed: %s\n", >+ nt_errstr(status))); >+ } >+ /* Either way we're done. */ >+ tevent_req_done(req); >+} >-- >1.9.0.279.gdc9e3eb > > >From 0b3b65adf24712c2aaaeafa144b743dda67e8385 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:36:47 -0800 >Subject: [PATCH 09/26] s3: smbd: SMB2 logoff - Add smbd_smb2_logoff_send(). > >Send function in making logoff async. Note the similarity >to the smbd_smb2_logoff_do() function, as this function >does the same thing when worken from the wait queue. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 43 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index b5fd873..c8cb926 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -956,6 +956,49 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > return smbd_smb2_request_done(req, outbody, NULL); > } > >+static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req) >+{ >+ NTSTATUS status; >+ struct tevent_req *req; >+ struct smbd_smb2_logout_state *state; >+ >+ req = tevent_req_create(mem_ctx, &state, >+ struct smbd_smb2_logout_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ state->smb2req = smb2req; >+ state->ev = ev; >+ >+ status = wait_for_outstanding_requests(state, req); >+ >+ /* >+ * NT_STATUS_RETRY means we're waiting >+ * for a cancelled request to complete. >+ */ >+ >+ if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { >+ return req; >+ } >+ >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("waiting for requests failed: %s\n", >+ nt_errstr(status))); >+ return tevent_req_post(req, ev); >+ } >+ >+ status = try_to_tear_down_session(state->smb2req); >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("tearing down session failed: %s\n", >+ nt_errstr(status))); >+ return tevent_req_post(req, ev); >+ } >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ > /*************************************************************** > Wait callback function called when we were woken up by an > SMB2 request we were waiting on completing. Checks to see >-- >1.9.0.279.gdc9e3eb > > >From a7b45512d3743fba1aef9178d9839150fa3c78b6 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:20:50 -0800 >Subject: [PATCH 10/26] s3: smbd: SMB2 logoff - Add smbd_smb2_logoff_recv(). > >Boilerplate async receive function. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index c8cb926..e6552e7 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -1057,3 +1057,15 @@ static void smbd_smb2_logoff_do(struct tevent_req *subreq) > /* Either way we're done. */ > tevent_req_done(req); > } >+ >+static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req) >+{ >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ tevent_req_received(req); >+ return NT_STATUS_OK; >+} >-- >1.9.0.279.gdc9e3eb > > >From c3c66c169869be647bab18a2b1957f89441c45e1 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:40:25 -0800 >Subject: [PATCH 11/26] s3: smbd: SMB2 logoff - Add > smbd_smb2_request_logoff_done(). > >Reply function for aync logoff. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 43 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index e6552e7..164c1eb 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -956,6 +956,49 @@ NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > return smbd_smb2_request_done(req, outbody, NULL); > } > >+static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) >+{ >+ struct smbd_smb2_request *smb2req = >+ tevent_req_callback_data(subreq, >+ struct smbd_smb2_request); >+ DATA_BLOB outbody; >+ NTSTATUS status; >+ NTSTATUS error; >+ >+ status = smbd_smb2_logoff_recv(subreq); >+ TALLOC_FREE(subreq); >+ if (!NT_STATUS_IS_OK(status)) { >+ error = smbd_smb2_request_error(smb2req, status); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ outbody = smbd_smb2_generate_outbody(smb2req, 0x04); >+ if (outbody.data == NULL) { >+ error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >+ SSVAL(outbody.data, 0x02, 0); /* reserved */ >+ >+ error = smbd_smb2_request_done(smb2req, outbody, NULL); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+} >+ > static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, > struct smbd_smb2_request *smb2req) >-- >1.9.0.279.gdc9e3eb > > >From 9433338b061ec1cb66c23a76bb10520eaf2baddd Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:45:09 -0800 >Subject: [PATCH 12/26] s3: smbd: SMB2 logoff - Add forward references for > asnyc logoff functions. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 6 ++++++ > 1 file changed, 6 insertions(+) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index 164c1eb..ae17b51 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -914,6 +914,12 @@ static NTSTATUS try_to_tear_down_session(struct smbd_smb2_request *smb2req) > return NT_STATUS_OK; > } > >+static struct tevent_req *smbd_smb2_logoff_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req); >+static NTSTATUS smbd_smb2_logoff_recv(struct tevent_req *req); >+static void smbd_smb2_request_logoff_done(struct tevent_req *subreq); >+ > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From b380a969750004f9c1a8f0e92ba615ca3e26ee2f Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 14:46:11 -0800 >Subject: [PATCH 13/26] s3: smbd: SMB2 logoff - Convert > smbd_smb2_request_process_logoff() to asnyc. > >Use standard _send()/_recv() idiom. > >Plumbs in all the previous 'not yet used' functions. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_sesssetup.c | 35 ++++++++--------------------------- > 1 file changed, 8 insertions(+), 27 deletions(-) > >diff --git a/source3/smbd/smb2_sesssetup.c b/source3/smbd/smb2_sesssetup.c >index ae17b51..6d6a7e5 100644 >--- a/source3/smbd/smb2_sesssetup.c >+++ b/source3/smbd/smb2_sesssetup.c >@@ -923,43 +923,24 @@ static void smbd_smb2_request_logoff_done(struct tevent_req *subreq); > NTSTATUS smbd_smb2_request_process_logoff(struct smbd_smb2_request *req) > { > NTSTATUS status; >- DATA_BLOB outbody; >+ struct tevent_req *subreq = NULL; > > status = smbd_smb2_request_verify_sizes(req, 0x04); > if (!NT_STATUS_IS_OK(status)) { > return smbd_smb2_request_error(req, status); > } > >- /* >- * TODO: cancel all outstanding requests on the session >- */ >- status = smbXsrv_session_logoff(req->session); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("smbd_smb2_request_process_logoff: " >- "smbXsrv_session_logoff() failed: %s\n", >- nt_errstr(status))); >- /* >- * If we hit this case, there is something completely >- * wrong, so we better disconnect the transport connection. >- */ >- return status; >+ subreq = smbd_smb2_logoff_send(req, req->sconn->ev_ctx, req); >+ if (subreq == NULL) { >+ return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); > } >+ tevent_req_set_callback(subreq, smbd_smb2_request_logoff_done, req); > > /* >- * we may need to sign the response, so we need to keep >- * the session until the response is sent to the wire. >+ * Wait a long time before going async on this to allow >+ * requests we're waiting on to finish. Set timeout to 10 secs. > */ >- talloc_steal(req, req->session); >- >- outbody = smbd_smb2_generate_outbody(req, 0x04); >- if (outbody.data == NULL) { >- return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); >- } >- >- SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >- SSVAL(outbody.data, 0x02, 0); /* reserved */ >- >- return smbd_smb2_request_done(req, outbody, NULL); >+ return smbd_smb2_request_pending_queue(req, subreq, 10000000); > } > > static void smbd_smb2_request_logoff_done(struct tevent_req *subreq) >-- >1.9.0.279.gdc9e3eb > > >From e4778165527a648d2c4bd5eac0a810f0ed15d261 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:10:19 -0800 >Subject: [PATCH 14/26] s3: smbd: SMB2 tdis - add > find_outstanding_tcon_request() > >Walk the outstanding SMB2 requests and return the >first one (not including the current request being processed) >on this session. Return NULL if there are no outstanding >requests on this session. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 48 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index e1f0987..db295a1 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -411,6 +411,54 @@ static NTSTATUS smbd_smb2_tree_connect_recv(struct tevent_req *req, > return NT_STATUS_OK; > } > >+/******************************************************** >+ Walk the outstanding SMB2 requests and return the >+ first one (not including the current request being processed) >+ on this tcon. Return NULL if there are no outstanding >+ requests on this session. >+********************************************************/ >+ >+static struct smbd_smb2_request *find_outstanding_tcon_request( >+ const struct smbd_smb2_request *smb2req) >+{ >+ struct smbd_smb2_request *preq; >+ >+ if (smb2req->tcon == NULL) { >+ return NULL; >+ } >+ for (preq = smb2req->sconn->smb2.requests; preq != NULL; preq = preq->next) { >+ if (preq == smb2req) { >+ /* Can't cancel current request. */ >+ continue; >+ } >+ if (preq->tcon != smb2req->tcon) { >+ /* Request on different tcon. */ >+ continue; >+ } >+ if (preq->compound_related) { >+ /* >+ * Never cancel anything in a compound >+ * request. Way too hard to deal with >+ * the result. >+ */ >+ continue; >+ } >+ if (preq->subreq == NULL) { >+ /* >+ * Can this happen (not really >+ * in progress) ? >+ */ >+ continue; >+ } >+ /* >+ * If we get here we've found a request >+ * we're going to cancel. >+ */ >+ break; >+ } >+ return preq; >+} >+ > NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From 8e00888cc58f2a10a70e0415169408d18b2a9992 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:17:26 -0800 >Subject: [PATCH 15/26] s3: smbd: SMB2 tdis - Add definition of struct > smbd_smb2_tdis_state. > >Not yet used - will be used in async tdis code. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index db295a1..aa18ea1 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -496,3 +496,8 @@ NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) > > return smbd_smb2_request_done(req, outbody, NULL); > } >+ >+struct smbd_smb2_tdis_state { >+ struct smbd_smb2_request *smb2req; >+ struct tevent_context *ev; >+}; >-- >1.9.0.279.gdc9e3eb > > >From ded3df51daf7d081c1c73f42f49135d9c28171b2 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:18:23 -0800 >Subject: [PATCH 16/26] s3: smbd: SMB2 tdis - Add tevent_wait.h header to > smb2_tcon.c > >Will be used in async tdis code. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 1 + > 1 file changed, 1 insertion(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index aa18ea1..bbf6ed6 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -26,6 +26,7 @@ > #include "auth.h" > #include "lib/param/loadparm.h" > #include "../lib/util/tevent_ntstatus.h" >+#include "lib/tevent_wait.h" > > static struct tevent_req *smbd_smb2_tree_connect_send(TALLOC_CTX *mem_ctx, > struct tevent_context *ev, >-- >1.9.0.279.gdc9e3eb > > >From 81e37d45eaac502532f16be8f0b1696718a4c977 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:23:53 -0800 >Subject: [PATCH 17/26] smbd: SMB2 tdis - Add utility function > wait_for_outstanding_requests(). > >This looks for an outstanding request on this tcon, >calls tevent_req_cancel() on it and then uses the new >SMB2 request wait mechanism smbd_smb2_wait_for_request_to_complete() >to add a tevent request to the wait queue associated >with the SMB2 request we just cancelled. > >Returns NT_STATUS_RETRY if we are waiting. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 46 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index bbf6ed6..9783d9d 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -502,3 +502,49 @@ struct smbd_smb2_tdis_state { > struct smbd_smb2_request *smb2req; > struct tevent_context *ev; > }; >+ >+static void smbd_smb2_tdis_do(struct tevent_req *subreq); >+ >+/*************************************************************** >+ Utility function to wait for outstanding SMB2 requests on >+ this tcon. >+ If we return NT_STATUS_RETRY we have set ourselves to wait >+ for another request to complete. >+***************************************************************/ >+ >+static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_tdis_state *state, >+ struct tevent_req *req) >+{ >+ struct smbd_smb2_request *smb2req = state->smb2req; >+ struct smbd_smb2_request *smb2_wait_req; >+ NTSTATUS status; >+ >+ /* >+ * Try and find a request to cancel. If we can, >+ * cancel it and tell ourselves to wait unti it's finished. >+ */ >+ smb2_wait_req = find_outstanding_tcon_request(smb2req); >+ if (smb2_wait_req != NULL) { >+ >+ tevent_req_cancel(smb2_wait_req->subreq); >+ >+ status = smbd_smb2_wait_for_request_to_complete( >+ smb2req, /* Request to wake up on completion. */ >+ smb2_wait_req, /* Request we're waiting on. */ >+ state->ev, /* Event context. */ >+ smbd_smb2_tdis_do, /* callback. */ >+ req); /* Private pointer. */ >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(0, ("tdis wait failed: %s\n", >+ nt_errstr(status))); >+ return status; >+ } >+ /* We're waiting on another SMB2 request. */ >+ return NT_STATUS_RETRY; >+ } >+ return NT_STATUS_OK; >+} >+ >+static void smbd_smb2_tdis_do(struct tevent_req *subreq) >+{ >+} >-- >1.9.0.279.gdc9e3eb > > >From a2a19ffc9844828c3fecfb6282b9297b17f61eb6 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:26:44 -0800 >Subject: [PATCH 18/26] smbd: SMB2 tdis - Add utility function > try_to_tear_down_tcon(). > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 17 +++++++++++++++++ > 1 file changed, 17 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index 9783d9d..ef9dc77 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -545,6 +545,23 @@ static NTSTATUS wait_for_outstanding_requests(struct smbd_smb2_tdis_state *state > return NT_STATUS_OK; > } > >+/*************************************************************** >+ Utility function to do the work of tearing down a connection. >+***************************************************************/ >+ >+static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) >+{ >+ NTSTATUS status = smbXsrv_tcon_disconnect(smb2req->tcon, smb2req->tcon->compat->vuid); >+ if (!NT_STATUS_IS_OK(status)) { >+ DEBUG(0, ("smbXsrv_tcon_disconnect() failed: %s\n", >+ nt_errstr(status))); >+ return status; >+ } >+ >+ TALLOC_FREE(smb2req->tcon); >+ return NT_STATUS_OK; >+} >+ > static void smbd_smb2_tdis_do(struct tevent_req *subreq) > { > } >-- >1.9.0.279.gdc9e3eb > > >From b019b29b75e8f007302cbddf75fe9864af2c3ac5 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 7 Mar 2014 10:30:29 -0800 >Subject: [PATCH 19/26] s3: smbd: SMB2 tdis - Add wait completion function > smbd_smb2_tdis_do(). > >Wait callback function called when we were woken up by an >SMB2 request we were waiting on completing. Checks to see >if we should still wait, and goes back to sleep if so, >otherwise tears down the tcon and finishes the request. > >When ready to tear down the tcon it calls change_to_root_user() >as SMB2_OP_TDIS has .as_root = true in smb2_server.c and we may >have processed other commands and so may have swiched user whilst >we were waiting. Thanks to Metze for pointing this out. > >This avoids any tevent reentrancy and is a clean, simple way >of handling deferred notification. Many thanks to Volker >for showing the way to do this inside smb2_close.c. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 55 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index ef9dc77..b973b11 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -562,6 +562,61 @@ static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) > return NT_STATUS_OK; > } > >+/*************************************************************** >+ Wait callback function called when we were woken up by an >+ SMB2 request we were waiting on completing. Checks to see >+ if we should still wait, and goes back to sleep if so, >+ otherwise tears down the tcon and finishes the request. >+***************************************************************/ >+ > static void smbd_smb2_tdis_do(struct tevent_req *subreq) > { >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct smbd_smb2_tdis_state *state = tevent_req_data( >+ req, struct smbd_smb2_tdis_state); >+ NTSTATUS status; >+ int ret; >+ >+ ret = tevent_wait_recv(subreq); >+ TALLOC_FREE(subreq); >+ if (ret != 0) { >+ DEBUG(10, ("tevent_wait_recv returned %s\n", >+ strerror(ret))); >+ /* >+ * Continue anyway, this should never happen >+ */ >+ } >+ >+ status = wait_for_outstanding_requests(state, req); >+ >+ if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { >+ /* >+ * NT_STATUS_RETRY means we're waiting >+ * for another cancelled request to complete. >+ */ >+ return; >+ } >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("waiting for requests failed: %s\n", >+ nt_errstr(status))); >+ tevent_req_done(req); >+ return; >+ } >+ >+ /* >+ * As we've been awoken, we may have changed >+ * uid in the meantime. Ensure we're still >+ * root (SMB2_OP_TDIS has .as_root = true). >+ */ >+ change_to_root_user(); >+ >+ status = try_to_tear_down_tcon(state->smb2req); >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("tearing down the tcon failed: %s\n", >+ nt_errstr(status))); >+ return; >+ } >+ /* Either way we're done. */ >+ tevent_req_done(req); > } >-- >1.9.0.279.gdc9e3eb > > >From d31496092c8245ecad5240dca6966df4fbf4dca6 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:40:35 -0800 >Subject: [PATCH 20/26] s3: smbd: SMB2 tdis - Add smbd_smb2_tdis_send(). > >Send function in making tdis async. Note the similarity >to the smbd_smb2_tdis_do() function, as this function >does the same thing when worken from the wait queue. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 44 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index b973b11..86fa7f6 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -562,6 +562,50 @@ static NTSTATUS try_to_tear_down_tcon(struct smbd_smb2_request *smb2req) > return NT_STATUS_OK; > } > >+static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req) >+{ >+ NTSTATUS status; >+ struct tevent_req *req; >+ struct smbd_smb2_tdis_state *state; >+ >+ req = tevent_req_create(mem_ctx, &state, >+ struct smbd_smb2_tdis_state); >+ if (req == NULL) { >+ return NULL; >+ } >+ state->smb2req = smb2req; >+ state->ev = ev; >+ >+ status = wait_for_outstanding_requests(state, req); >+ >+ /* >+ * NT_STATUS_RETRY means we're waiting >+ * for a cancelled request to complete. >+ */ >+ >+ if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) { >+ return req; >+ } >+ >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("waiting for requests failed: %s\n", >+ nt_errstr(status))); >+ return tevent_req_post(req, ev); >+ } >+ >+ status = try_to_tear_down_tcon(state->smb2req); >+ if (tevent_req_nterror(req, status)) { >+ DEBUG(0, ("tearing down the tcon failed: %s\n", >+ nt_errstr(status))); >+ return tevent_req_post(req, ev); >+ } >+ /* Either way, we're done. */ >+ tevent_req_done(req); >+ return tevent_req_post(req, ev); >+} >+ > /*************************************************************** > Wait callback function called when we were woken up by an > SMB2 request we were waiting on completing. Checks to see >-- >1.9.0.279.gdc9e3eb > > >From b2593b3f573c1db00ee36f1848ab306a56b37e42 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:42:02 -0800 >Subject: [PATCH 21/26] s3: smbd: SMB2 tdis - Add smbd_smb2_tdis_recv(). > >Boilerplate async receive function. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index 86fa7f6..ec4e444 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -664,3 +664,15 @@ static void smbd_smb2_tdis_do(struct tevent_req *subreq) > /* Either way we're done. */ > tevent_req_done(req); > } >+ >+static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req) >+{ >+ NTSTATUS status; >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ tevent_req_received(req); >+ return status; >+ } >+ tevent_req_received(req); >+ return NT_STATUS_OK; >+} >-- >1.9.0.279.gdc9e3eb > > >From a9ded2e2baa23b5fcab8b7f87db1d6e7672551ac Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:44:12 -0800 >Subject: [PATCH 22/26] s3: smbd: SMB2 tdis - Add > smbd_smb2_request_tdis_done(). > >Reply function for aync tdis. > >Not yet used. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 43 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 43 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index ec4e444..5826073 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -498,6 +498,49 @@ NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) > return smbd_smb2_request_done(req, outbody, NULL); > } > >+static void smbd_smb2_request_tdis_done(struct tevent_req *subreq) >+{ >+ struct smbd_smb2_request *smb2req = >+ tevent_req_callback_data(subreq, >+ struct smbd_smb2_request); >+ DATA_BLOB outbody; >+ NTSTATUS status; >+ NTSTATUS error; >+ >+ status = smbd_smb2_tdis_recv(subreq); >+ TALLOC_FREE(subreq); >+ if (!NT_STATUS_IS_OK(status)) { >+ error = smbd_smb2_request_error(smb2req, status); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ outbody = smbd_smb2_generate_outbody(smb2req, 0x04); >+ if (outbody.data == NULL) { >+ error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+ return; >+ } >+ >+ SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >+ SSVAL(outbody.data, 0x02, 0); /* reserved */ >+ >+ error = smbd_smb2_request_done(smb2req, outbody, NULL); >+ if (!NT_STATUS_IS_OK(error)) { >+ smbd_server_connection_terminate(smb2req->sconn, >+ nt_errstr(error)); >+ return; >+ } >+} >+ > struct smbd_smb2_tdis_state { > struct smbd_smb2_request *smb2req; > struct tevent_context *ev; >-- >1.9.0.279.gdc9e3eb > > >From 54efc50cf38bb0d97c269ca04efe49251b6adaa7 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:45:47 -0800 >Subject: [PATCH 23/26] s3: smbd: SMB2 tdis - Add forward references for asnyc > tdis functions. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 6 ++++++ > 1 file changed, 6 insertions(+) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index 5826073..3c338c4 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -460,6 +460,12 @@ static struct smbd_smb2_request *find_outstanding_tcon_request( > return preq; > } > >+static struct tevent_req *smbd_smb2_tdis_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct smbd_smb2_request *smb2req); >+static NTSTATUS smbd_smb2_tdis_recv(struct tevent_req *req); >+static void smbd_smb2_request_tdis_done(struct tevent_req *subreq); >+ > NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) > { > NTSTATUS status; >-- >1.9.0.279.gdc9e3eb > > >From 53ae24a2dbc0900d85429585e26efdde900e1bca Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 6 Mar 2014 15:49:13 -0800 >Subject: [PATCH 24/26] s3: smbd: SMB2 tdis - Convert > smbd_smb2_request_process_tdis() to asnyc. > >Use standard _send()/_recv() idiom. > >Plumbs in all the previous 'not yet used' functions. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source3/smbd/smb2_tcon.c | 33 +++++++++------------------------ > 1 file changed, 9 insertions(+), 24 deletions(-) > >diff --git a/source3/smbd/smb2_tcon.c b/source3/smbd/smb2_tcon.c >index 3c338c4..44d1bdc 100644 >--- a/source3/smbd/smb2_tcon.c >+++ b/source3/smbd/smb2_tcon.c >@@ -469,39 +469,24 @@ static void smbd_smb2_request_tdis_done(struct tevent_req *subreq); > NTSTATUS smbd_smb2_request_process_tdis(struct smbd_smb2_request *req) > { > NTSTATUS status; >- DATA_BLOB outbody; >+ struct tevent_req *subreq = NULL; > > status = smbd_smb2_request_verify_sizes(req, 0x04); > if (!NT_STATUS_IS_OK(status)) { > return smbd_smb2_request_error(req, status); > } > >- /* >- * TODO: cancel all outstanding requests on the tcon >- */ >- status = smbXsrv_tcon_disconnect(req->tcon, req->tcon->compat->vuid); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(0, ("smbd_smb2_request_process_tdis: " >- "smbXsrv_tcon_disconnect() failed: %s\n", >- nt_errstr(status))); >- /* >- * If we hit this case, there is something completely >- * wrong, so we better disconnect the transport connection. >- */ >- return status; >- } >- >- TALLOC_FREE(req->tcon); >- >- outbody = smbd_smb2_generate_outbody(req, 0x04); >- if (outbody.data == NULL) { >+ subreq = smbd_smb2_tdis_send(req, req->sconn->ev_ctx, req); >+ if (subreq == NULL) { > return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY); > } >+ tevent_req_set_callback(subreq, smbd_smb2_request_tdis_done, req); > >- SSVAL(outbody.data, 0x00, 0x04); /* struct size */ >- SSVAL(outbody.data, 0x02, 0); /* reserved */ >- >- return smbd_smb2_request_done(req, outbody, NULL); >+ /* >+ * Wait a long time before going async on this to allow >+ * requests we're waiting on to finish. Set timeout to 10 secs. >+ */ >+ return smbd_smb2_request_pending_queue(req, subreq, 10000000); > } > > static void smbd_smb2_request_tdis_done(struct tevent_req *subreq) >-- >1.9.0.279.gdc9e3eb > > >From cbdbf574169db74f67f937ad1e1858467a795aad Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 28 Jan 2014 14:07:26 -0800 >Subject: [PATCH 25/26] s4: smbtorture: Update the torture_smb2_notify_ulogoff > test to demonstrate the problem. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/notify.c | 13 +++++++++++-- > 1 file changed, 11 insertions(+), 2 deletions(-) > >diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c >index e83b099..e9664d3 100644 >--- a/source4/torture/smb2/notify.c >+++ b/source4/torture/smb2/notify.c >@@ -69,6 +69,13 @@ > goto done; \ > }} while (0) > >+#define WAIT_FOR_ASYNC_RESPONSE(req) \ >+ while (!req->cancel.can_cancel && req->state <= SMB2_REQUEST_RECV) { \ >+ if (tevent_loop_once(torture->ev) != 0) { \ >+ break; \ >+ } \ >+ } >+ > #define BASEDIR "test_notify" > #define FNAME "smb2-notify01.dat" > >@@ -1280,7 +1287,7 @@ static bool torture_smb2_notify_ulogoff(struct torture_context *torture, > CHECK_STATUS(status, NT_STATUS_OK); > > io.smb2.in.create_disposition = NTCREATEX_DISP_OPEN; >- status = smb2_create(tree2, torture, &(io.smb2)); >+ status = smb2_create(tree1, torture, &(io.smb2)); > CHECK_STATUS(status, NT_STATUS_OK); > h1 = io.smb2.out.file.handle; > >@@ -1295,7 +1302,9 @@ static bool torture_smb2_notify_ulogoff(struct torture_context *torture, > > req = smb2_notify_send(tree1, &(notify.smb2)); > >- status = smb2_logoff(tree2->session); >+ WAIT_FOR_ASYNC_RESPONSE(req); >+ >+ status = smb2_logoff(tree1->session); > CHECK_STATUS(status, NT_STATUS_OK); > > status = smb2_notify_recv(req, torture, &(notify.smb2)); >-- >1.9.0.279.gdc9e3eb > > >From 144021bfd56f5f9fe3fb628e0cf207c7630890e9 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 24 Feb 2014 10:44:59 -0800 >Subject: [PATCH 26/26] s4: smbtorture: Add a proper change_notify going async > followed by tdis test. > >[Bug 10344] SessionLogoff on a signed connection with an outstanding notify request crashes smbd. > >https://bugzilla.samba.org/show_bug.cgi?id=10344 > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > source4/torture/smb2/notify.c | 68 ++++++++++++++++++++++++++++++++++++++++++- > 1 file changed, 67 insertions(+), 1 deletion(-) > >diff --git a/source4/torture/smb2/notify.c b/source4/torture/smb2/notify.c >index e9664d3..650337e 100644 >--- a/source4/torture/smb2/notify.c >+++ b/source4/torture/smb2/notify.c >@@ -1195,7 +1195,7 @@ static bool torture_smb2_notify_tree_disconnect( > smb2_deltree(tree, BASEDIR); > smb2_util_rmdir(tree, BASEDIR); > >- torture_comment(torture, "TESTING CHANGE NOTIFY FOLLOWED BY " >+ torture_comment(torture, "TESTING CHANGE NOTIFY+CANCEL FOLLOWED BY " > "TREE-DISCONNECT\n"); > > /* >@@ -1247,6 +1247,71 @@ done: > } > > /* >+ testing of change notifies followed by a tdis - no cancel >+*/ >+ >+static bool torture_smb2_notify_tree_disconnect_1( >+ struct torture_context *torture, >+ struct smb2_tree *tree) >+{ >+ bool ret = true; >+ NTSTATUS status; >+ union smb_notify notify; >+ union smb_open io; >+ struct smb2_handle h1; >+ struct smb2_request *req; >+ >+ smb2_deltree(tree, BASEDIR); >+ smb2_util_rmdir(tree, BASEDIR); >+ >+ torture_comment(torture, "TESTING CHANGE NOTIFY ASYNC FOLLOWED BY " >+ "TREE-DISCONNECT\n"); >+ >+ /* >+ get a handle on the directory >+ */ >+ ZERO_STRUCT(io.smb2); >+ io.generic.level = RAW_OPEN_SMB2; >+ io.smb2.in.create_flags = 0; >+ io.smb2.in.desired_access = SEC_FILE_ALL; >+ io.smb2.in.create_options = NTCREATEX_OPTIONS_DIRECTORY; >+ io.smb2.in.file_attributes = FILE_ATTRIBUTE_NORMAL; >+ io.smb2.in.share_access = NTCREATEX_SHARE_ACCESS_READ | >+ NTCREATEX_SHARE_ACCESS_WRITE; >+ io.smb2.in.alloc_size = 0; >+ io.smb2.in.create_disposition = NTCREATEX_DISP_CREATE; >+ io.smb2.in.impersonation_level = SMB2_IMPERSONATION_ANONYMOUS; >+ io.smb2.in.security_flags = 0; >+ io.smb2.in.fname = BASEDIR; >+ >+ status = smb2_create(tree, torture, &(io.smb2)); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ h1 = io.smb2.out.file.handle; >+ >+ /* ask for a change notify, >+ on file or directory name changes */ >+ ZERO_STRUCT(notify.smb2); >+ notify.smb2.level = RAW_NOTIFY_SMB2; >+ notify.smb2.in.buffer_size = 1000; >+ notify.smb2.in.completion_filter = FILE_NOTIFY_CHANGE_NAME; >+ notify.smb2.in.file.handle = h1; >+ notify.smb2.in.recursive = true; >+ >+ req = smb2_notify_send(tree, &(notify.smb2)); >+ WAIT_FOR_ASYNC_RESPONSE(req); >+ >+ status = smb2_tdis(tree); >+ CHECK_STATUS(status, NT_STATUS_OK); >+ >+ status = smb2_notify_recv(req, torture, &(notify.smb2)); >+ CHECK_VAL(notify.smb2.out.num_changes, 0); >+ >+done: >+ smb2_deltree(tree, BASEDIR); >+ return ret; >+} >+ >+/* > basic testing of change notifies followed by a ulogoff > */ > >@@ -2000,6 +2065,7 @@ struct torture_suite *torture_smb2_notify_init(void) > torture_suite_add_2smb2_test(suite, "dir", torture_smb2_notify_dir); > torture_suite_add_2smb2_test(suite, "mask", torture_smb2_notify_mask); > torture_suite_add_1smb2_test(suite, "tdis", torture_smb2_notify_tree_disconnect); >+ torture_suite_add_1smb2_test(suite, "tdis1", torture_smb2_notify_tree_disconnect_1); > torture_suite_add_2smb2_test(suite, "mask-change", torture_smb2_notify_mask_change); > torture_suite_add_2smb2_test(suite, "logoff", torture_smb2_notify_ulogoff); > torture_suite_add_1smb2_test(suite, "tree", torture_smb2_notify_tree); >-- >1.9.0.279.gdc9e3eb >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 10344
:
9547
|
9619
|
9620
|
9736
|
9761
|
9770
|
9772
|
9773
|
9780
|
9815
|
9816
|
9817
|
9818