fsrvp: keep fss agent conn struct across async VFS reqs
authorDavid Disseldorp <ddiss@samba.org>
Sun, 7 Oct 2012 15:10:52 +0000 (17:10 +0200)
committerDavid Disseldorp <ddiss@samba.org>
Mon, 15 Apr 2013 16:15:20 +0000 (18:15 +0200)
Prior to this change, the VFS connection struct was created and
destroyed for each VFS async snapshot _send _recv call.

This behavour is not suitable for transparent VFS modules which pass
on the VFS handle to subsequent modules (e.g. vfs_time_audit).

source3/rpc_server/fss/srv_fss_agent.c

index 28adb359c4cdc5ecbe252e52fbc6d8d68802f659..25f45a01c7c000df3b0ec2a55cd90f3cceaad6de 100644 (file)
@@ -69,7 +69,7 @@ static uint32_t fss_ntstatus_map(NTSTATUS status)
        return E_OUTOFMEMORY;   /* FIXME */
 }
 
-static NTSTATUS fss_vfs_conn_become(TALLOC_CTX *mem_ctx,
+static NTSTATUS fss_vfs_conn_create(TALLOC_CTX *mem_ctx,
                                    struct tevent_context *ev,
                                    struct messaging_context *msg_ctx,
                                    struct auth_session_info *session_info,
@@ -96,11 +96,6 @@ static NTSTATUS fss_vfs_conn_become(TALLOC_CTX *mem_ctx,
                goto err_free_conn;
        }
 
-       if (!become_user_by_session(conn, session_info)) {
-               DEBUG(0, ("failed to become user\n"));
-               status = NT_STATUS_ACCESS_DENIED;
-               goto err_free_conn;
-       }
        *conn_out = conn;
 
        return NT_STATUS_OK;
@@ -112,9 +107,8 @@ err_free_conn:
        return status;
 }
 
-static void fss_vfs_conn_unbecome(struct connection_struct *conn)
+static void fss_vfs_conn_destroy(struct connection_struct *conn)
 {
-       unbecome_user();
        /* vfs_ChDir(conn, oldcwd); needed? */
        SMB_VFS_DISCONNECT(conn);
        conn_free(conn);
@@ -449,14 +443,22 @@ uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
                return E_OUTOFMEMORY;
        }
 
-       status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
+       status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
                                     p->msg_ctx, p->session_info, snum, &conn);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
                return E_ACCESSDENIED;
        }
+       if (!become_user_by_session(conn, p->session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               fss_vfs_conn_destroy(conn);
+               talloc_free(tmp_ctx);
+               return E_ACCESSDENIED;
+       }
+
        status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx, path_name, &base_vol);
-       fss_vfs_conn_unbecome(conn);
+       unbecome_user();
+       fss_vfs_conn_destroy(conn);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
                return FSRVP_E_NOT_SUPPORTED;
@@ -542,7 +544,110 @@ uint32_t _fss_AddToShadowCopySet(struct pipes_struct *p,
        return 0;
 }
 
-struct fss_commit_state {
+struct fss_sc_commit_state {
+       struct auth_session_info *session_info;
+       struct connection_struct *conn;
+       char *base_path;
+       char *snap_path;
+};
+
+static void commit_sc_with_conn_done(struct tevent_req *subreq);
+
+static struct tevent_req *commit_sc_with_conn_send(TALLOC_CTX *mem_ctx,
+                                       struct tevent_context *ev,
+                                       struct messaging_context *msg_ctx,
+                                       struct auth_session_info *session_info,
+                                       struct fss_sc *sc)
+{
+       struct tevent_req *req;
+       struct tevent_req *subreq;
+       struct fss_sc_commit_state *sc_commit_state;
+       NTSTATUS status;
+       bool rw;
+
+       req = tevent_req_create(mem_ctx, &sc_commit_state,
+                               struct fss_sc_commit_state);
+       if (req == NULL) {
+               return NULL;
+       }
+
+       sc_commit_state->session_info = session_info;
+
+       status = fss_vfs_conn_create(sc_commit_state,
+                                    ev, msg_ctx, session_info,
+                                    sc->smaps->snum,
+                                    &sc_commit_state->conn);
+       if (tevent_req_nterror(req, status)) {
+               return tevent_req_post(req, ev);
+       }
+
+       if (!become_user_by_session(sc_commit_state->conn, session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               fss_vfs_conn_destroy(sc_commit_state->conn);
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return tevent_req_post(req, ev);
+       }
+       rw = ((sc->sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
+       subreq = SMB_VFS_SNAP_CREATE_SEND(sc_commit_state->conn,
+                                         sc_commit_state,
+                                         ev, sc->volume_name,
+                                         &sc->create_ts, rw);
+       unbecome_user();
+       if (tevent_req_nomem(subreq, req)) {
+               fss_vfs_conn_destroy(sc_commit_state->conn);
+               return tevent_req_post(req, ev);
+       }
+       tevent_req_set_callback(subreq, commit_sc_with_conn_done, req);
+       return req;
+}
+
+static void commit_sc_with_conn_done(struct tevent_req *subreq)
+{
+       NTSTATUS status;
+       struct tevent_req *req
+               = tevent_req_callback_data(subreq, struct tevent_req);
+       struct fss_sc_commit_state *sc_commit_state
+               = tevent_req_data(req, struct fss_sc_commit_state);
+
+       if (!become_user_by_session(sc_commit_state->conn,
+                                   sc_commit_state->session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               tevent_req_done(req);
+               return;
+       }
+       status = SMB_VFS_SNAP_CREATE_RECV(sc_commit_state->conn, subreq,
+                                         sc_commit_state,
+                                         &sc_commit_state->base_path,
+                                         &sc_commit_state->snap_path);
+       if (tevent_req_nterror(req, status)) {
+               DEBUG(0, ("snap create failed: %s\n", nt_errstr(status)));
+       }
+       unbecome_user();
+       fss_vfs_conn_destroy(sc_commit_state->conn);
+       tevent_req_done(req);
+}
+
+static NTSTATUS commit_sc_with_conn_recv(struct tevent_req *req,
+                                        TALLOC_CTX *mem_ctx,
+                                        char **base_path, char **snap_path)
+{
+       NTSTATUS status;
+       struct fss_sc_commit_state *sc_commit_state
+               = tevent_req_data(req, struct fss_sc_commit_state);
+
+       if (tevent_req_is_nterror(req, &status)) {
+               tevent_req_received(req);
+               return status;
+       }
+       *base_path = talloc_strdup(mem_ctx, sc_commit_state->base_path);
+       *snap_path = talloc_strdup(mem_ctx, sc_commit_state->snap_path);
+       tevent_req_received(req);
+
+       return NT_STATUS_OK;
+}
+
+struct fss_sc_set_commit_state {
        struct auth_session_info *session_info;
        struct GUID sc_set_id;          /* use guid as handle in case of abort */
        uint32_t dispatch_count;
@@ -550,7 +655,7 @@ struct fss_commit_state {
        uint32_t bad_recv_count;        /* number of failed completions */
        NTSTATUS status;
 };
-static void fss_commit_vfs_done(struct tevent_req *subreq);
+static void fss_commit_sc_set_done(struct tevent_req *subreq);
 
 struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
                                                 TALLOC_CTX *mem_ctx,
@@ -558,13 +663,12 @@ struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
                                        struct fss_CommitShadowCopySet *r)
 {
        struct tevent_req *req;
-       struct fss_commit_state *commit_state = NULL;
+       struct fss_sc_set_commit_state *commit_state = NULL;
        struct fss_sc_set *sc_set;
        struct fss_sc *sc;
-       bool rw;
 
        req = tevent_req_create(mem_ctx, &commit_state,
-                               struct fss_commit_state);
+                               struct fss_sc_set_commit_state);
        if (req == NULL) {
                return NULL;
        }
@@ -592,25 +696,13 @@ struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
        /* TODO stop Message Sequence Timer */
        commit_state->session_info = p->session_info;
        commit_state->sc_set_id = sc_set->id;
-       rw = ((sc_set->context & ATTR_AUTO_RECOVERY) == ATTR_AUTO_RECOVERY);
 
        for (sc = sc_set->scs; sc; sc = sc->next) {
-               struct tevent_req *vfs_req = NULL;
-               struct connection_struct *conn;
-               NTSTATUS status;
-               /* XXX error path is a bit complex here */
-               status = fss_vfs_conn_become(commit_state,
-                                            ev, p->msg_ctx, p->session_info,
-                                            sc->smaps->snum, &conn);
-               if (NT_STATUS_IS_OK(status)) {
-                       status = NT_STATUS_NO_MEMORY;
-                       vfs_req = SMB_VFS_SNAP_CREATE_SEND(conn, commit_state,
-                                                          ev, sc->volume_name,
-                                                          &sc->create_ts, rw);
-                       fss_vfs_conn_unbecome(conn);
-               }
+               struct tevent_req *vfs_req;
+               vfs_req = commit_sc_with_conn_send(commit_state, ev, p->msg_ctx,
+                                                  p->session_info, sc);
                if (vfs_req == NULL) {
-                       commit_state->status = status;
+                       commit_state->status = NT_STATUS_NO_MEMORY;
                        if (commit_state->dispatch_count == 0) {
                                /* nothing dispatched, return immediately */
                                tevent_req_nterror(sc_set->commit_req,
@@ -625,7 +717,7 @@ struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
                        }
                }
                /* XXX set timeout r->in.TimeOutInMilliseconds */
-               tevent_req_set_callback(vfs_req, fss_commit_vfs_done, sc);
+               tevent_req_set_callback(vfs_req, fss_commit_sc_set_done, sc);
                sc->vfs_req = vfs_req;
                commit_state->dispatch_count++;
        }
@@ -634,29 +726,19 @@ struct tevent_req *_fss_CommitShadowCopySet_send(struct tevent_context *ev,
        return sc_set->commit_req;
 }
 
-static void fss_commit_vfs_done(struct tevent_req *subreq)
+static void fss_commit_sc_set_done(struct tevent_req *subreq)
 {
-       /* FIXME use a sc handle */
        struct fss_sc *sc = tevent_req_callback_data(subreq,
                                                     struct fss_sc);
        struct tevent_req *req = sc->sc_set->commit_req;
-       struct fss_commit_state *commit_state = tevent_req_data(req,
-                                                 struct fss_commit_state);
+       struct fss_sc_set_commit_state *commit_state = tevent_req_data(req,
+                                               struct fss_sc_set_commit_state);
        char *snap_path;
        char *base_path;
        NTSTATUS status;
-       struct connection_struct *conn;
 
        commit_state->recv_count++;
-       status = fss_vfs_conn_become(commit_state, server_event_context(),
-                                    server_messaging_context(),
-                                    commit_state->session_info,
-                                    sc->smaps->snum, &conn);
-       if (NT_STATUS_IS_OK(status)) {
-               status = SMB_VFS_SNAP_CREATE_RECV(conn, subreq, sc,
-                                                 &base_path, &snap_path);
-               fss_vfs_conn_unbecome(conn);
-       }
+       status = commit_sc_with_conn_recv(subreq, sc, &base_path, &snap_path);
        if (NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("good snap create recv %d of %d\n",
                           commit_state->recv_count,
@@ -664,7 +746,7 @@ static void fss_commit_vfs_done(struct tevent_req *subreq)
                sc->sc_path = snap_path;
        } else {
                DEBUG(0, ("snap create failed for shadow copy of "
-                         "%s\n", base_path));
+                         "%s\n", sc->volume_name));
                commit_state->bad_recv_count++;
                commit_state->status = status;  /* may overwrite previous failure */
        }
@@ -694,8 +776,8 @@ static void fss_commit_vfs_done(struct tevent_req *subreq)
 
 uint32_t _fss_CommitShadowCopySet_recv(struct tevent_req *req)
 {
-       struct fss_commit_state *commit_state
-                               = tevent_req_data(req, struct fss_commit_state);
+       struct fss_sc_set_commit_state *commit_state
+                       = tevent_req_data(req, struct fss_sc_set_commit_state);
 
        if (!NT_STATUS_IS_OK(commit_state->status)) {
                uint32_t ret;
@@ -1032,15 +1114,23 @@ uint32_t _fss_IsPathSupported(struct pipes_struct *p,
                return E_INVALIDARG;
        }
 
-       status = fss_vfs_conn_become(tmp_ctx, server_event_context(),
+       status = fss_vfs_conn_create(tmp_ctx, server_event_context(),
                                     p->msg_ctx, p->session_info, snum, &conn);
        if (!NT_STATUS_IS_OK(status)) {
+               talloc_free(tmp_ctx);
+               return E_ACCESSDENIED;
+       }
+       if (!become_user_by_session(conn, p->session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               talloc_free(tmp_ctx);
+               fss_vfs_conn_destroy(conn);
                return E_ACCESSDENIED;
        }
        status = SMB_VFS_SNAP_CHECK_PATH(conn, tmp_ctx,
                                         lp_pathname(tmp_ctx, snum),
                                         &base_vol);
-       fss_vfs_conn_unbecome(conn);
+       unbecome_user();
+       fss_vfs_conn_destroy(conn);
        if (!NT_STATUS_IS_OK(status)) {
                talloc_free(tmp_ctx);
                return FSRVP_E_NOT_SUPPORTED;
@@ -1189,6 +1279,7 @@ struct fss_delete_state {
        struct fss_sc_set *sc_set;
        struct fss_sc *sc;
        struct fss_sc_smap *sc_smap;
+       struct connection_struct *conn;
        int snum;
 };
 static void fss_delete_vfs_done(struct tevent_req *subreq);
@@ -1205,7 +1296,6 @@ struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
        struct tevent_req *vfs_req = NULL;
        struct fss_sc_smap *sc_smap;
        char *share;
-       struct connection_struct *conn;
        NTSTATUS status;
 
        req = tevent_req_create(mem_ctx, &delete_state,
@@ -1273,17 +1363,25 @@ struct tevent_req *_fss_DeleteShareMapping_send(struct tevent_context *ev,
                return tevent_req_post(req, ev);
        }
 
-       status = fss_vfs_conn_become(delete_state, ev, p->msg_ctx,
+       status = fss_vfs_conn_create(delete_state, ev, p->msg_ctx,
                                     delete_state->session_info,
-                                    delete_state->snum, &conn);
+                                    delete_state->snum,
+                                    &delete_state->conn);
        if (tevent_req_nterror(req, status)) {
                return tevent_req_post(req, ev);
        }
+       if (!become_user_by_session(delete_state->conn, p->session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               fss_vfs_conn_destroy(delete_state->conn);
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
+               return tevent_req_post(req, ev);
+       }
 
-       vfs_req = SMB_VFS_SNAP_DELETE_SEND(conn, delete_state, ev,
-                                          sc->volume_name, sc->sc_path);
-       fss_vfs_conn_unbecome(conn);
+       vfs_req = SMB_VFS_SNAP_DELETE_SEND(delete_state->conn, delete_state,
+                                          ev, sc->volume_name, sc->sc_path);
+       unbecome_user();
        if (tevent_req_nomem(vfs_req, req)) {
+               fss_vfs_conn_destroy(delete_state->conn);
                return tevent_req_post(req, ev);
        }
 
@@ -1301,18 +1399,18 @@ static void fss_delete_vfs_done(struct tevent_req *subreq)
        struct fss_delete_state *delete_state = tevent_req_data(req,
                                                  struct fss_delete_state);
        NTSTATUS status;
-       struct connection_struct *conn;
 
-       status = fss_vfs_conn_become(delete_state, server_event_context(),
-                                    server_messaging_context(),
-                                    delete_state->session_info,
-                                    delete_state->snum, &conn);
-       if (tevent_req_nterror(req, status)) {
+       if (!become_user_by_session(delete_state->conn,
+                                   delete_state->session_info)) {
+               DEBUG(0, ("failed to become user\n"));
+               fss_vfs_conn_destroy(delete_state->conn);
+               tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
                return;
        }
 
-       status = SMB_VFS_SNAP_DELETE_RECV(conn, subreq);
-       fss_vfs_conn_unbecome(conn);
+       status = SMB_VFS_SNAP_DELETE_RECV(delete_state->conn, subreq);
+       unbecome_user();
+       fss_vfs_conn_destroy(delete_state->conn);
        if (tevent_req_nterror(req, status)) {
                DEBUG(0, ("bad snap delete recv: %s\n",
                          nt_errstr(status)));