From: Ralph Boehme Date: Fri, 28 Dec 2018 12:08:14 +0000 (+0100) Subject: Revert "s3: vfs: add smb_vfs_ev_glue" X-Git-Tag: talloc-2.1.15~193 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cedbfbd9b86c9c4f915b19b341cada4c93db7cff;p=thirdparty%2Fsamba.git Revert "s3: vfs: add smb_vfs_ev_glue" This reverts commit 1251a536df4b1df58d9ddacab03d3ebe6f4e5b60. See the discussion in https://lists.samba.org/archive/samba-technical/2018-December/131731.html for the reasoning behind this revert. Signed-off-by: Ralph Boehme Reviewed-by: Volker Lendecke Reviewed-by: Stefan Metzmacher --- diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 6516869b24e..959dd405915 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -257,8 +257,6 @@ /* Version 39 - Remove struct dfree_cached_info pointer from connection struct */ /* Bump to version 40, Samba 4.10 will ship with that */ -/* Version 40 - Introduce smb_vfs_ev_glue infrastructure. */ -/* Version 40 - Add vfs_not_implemented_* helper functions. */ /* Version 40 - Add SMB_VFS_GETXATTRAT_SEND/RECV */ /* Version 40 - Add SMB_VFS_GET_DOS_ATTRIBUTES_SEND/RECV */ @@ -283,9 +281,6 @@ struct smb_file_time; struct blocking_lock_record; struct smb_filename; struct dfs_GetDFSReferral; -struct tevent_context; -struct pthreadpool_tevent; -struct smb_vfs_ev_glue; typedef union unid_t { uid_t uid; @@ -1553,31 +1548,6 @@ void *vfs_fetch_fsp_extension(vfs_handle_struct *handle, files_struct *fsp); void smb_vfs_assert_all_fns(const struct vfs_fn_pointers* fns, const char *module); -/* - * Notice the "Design of the smb_vfs_ev_glue infrastructure" - * comment in source3/smbd/vfs.c! - * - * This explains smb_vfs_ev_glue infrastructure in detail. - */ -struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg); -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg); -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg); -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg); -const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg); -struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx, - struct tevent_context *user_ev, - struct pthreadpool_tevent *user_tp_fd_safe, - struct pthreadpool_tevent *user_tp_path_safe, - struct pthreadpool_tevent *user_tp_chdir_safe, - struct tevent_context *root_ev, - struct pthreadpool_tevent *root_tp_fd_safe, - struct pthreadpool_tevent *root_tp_path_safe, - struct pthreadpool_tevent *root_tp_chdir_safe); -struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch( - TALLOC_CTX *mem_ctx, - const struct smb_vfs_ev_glue *return_evg, - const struct smb_vfs_ev_glue *run_evg); - /* * Helper functions from source3/modules/vfs_not_implemented.c */ diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 0cf8f8caa1d..5e0ca091f7b 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1452,838 +1452,6 @@ struct file_id vfs_file_id_from_sbuf(connection_struct *conn, const SMB_STRUCT_S return SMB_VFS_FILE_ID_CREATE(conn, sbuf); } -/* - * Design of the smb_vfs_ev_glue infrastructure: - * - * smb_vfs_ev_glue makes it possible to pass - * down an tevent_context and pthreadpool_tevent - * used for impersonation through the SMB_VFS stack. - * - * tevent_req based function take an tevent_context as - * there 2nd argument, e.g.: - * - * struct tevent_req *something_send(TALLOC_CTX *mem_ctx, - * struct tevent_context *ev, - * ...); - * - * For the SMB_VFS stack we'll use the following: - * - * struct tevent_req *SMB_VFS_SOMETHING_SEND(TALLOC_CTX *mem_ctx, - * const struct smb_vfs_ev_glue *evg, - * ...); - * - * Typically the 'evg' is just passed through the stack down - * to vfs_default.c. In order to do real work an - * tevent_context and pthreadpool_tevent are required - * to do call a 'somthing()' syscall in an async fashion. - * Therefore it will the following to get the pointer - * back out of evg: - * - * ev = smb_vfs_ev_glue_ev_ctx(evg); - * tp = smb_vfs_ev_glue_tp_chdir_safe(evg); - * - * If some function in the stack is sure it needs to run as root - * to get some information (after careful checks!), it used - * to frame that work into become_root()/unbecome_root(). - * This can't work when using async functions! - * Now it's possible to use something like this (simplified!): - * - * ev = smb_vfs_ev_glue_ev_ctx(evg); - * root_evg = smb_vfs_ev_glue_get_root_glue(evg); - * subreq = SMB_VFS_SOMETHING_NEXT_SEND(state, root_evg, ...); - * if (tevent_req_nomem(subreq, req)) { - * return tevent_req_post(req, ev); - * } - * tevent_req_set_callback(subreq, module_something_done, req); - * - * return req; - * - * static void module_something_done(struct tevent_req *subreq) - * { - * ... - * - * status = SMB_VFS_SOMETHING_NEXT_RECV(subreq, &state->aio_state); - * TALLOC_FREE(subreq); - * - * tevent_req_done(req); - * } - * - * In the code above the something_send_fn() function of the next - * module in the stack will be called as root. - * The smb_vfs_call_something_*() glue code, which is the magic - * behind the SMB_VFS_SOMETHING[_NEXT]_{SEND,RECV}() macros, - * will look like this: - * - * struct smb_vfs_call_something_state { - * ssize_t (*recv_fn)(struct tevent_req *req, - * struct vfs_aio_state *aio_state, - * ...); - * ssize_t retval; - * struct vfs_aio_state vfs_aio_state; - * ... - * }; - * - * static void smb_vfs_call_something_done(struct tevent_req *subreq); - * - * struct tevent_req *smb_vfs_call_something_send( - * TALLOC_CTX *mem_ctx, - * const struct smb_vfs_ev_glue *evg, - * struct vfs_handle_struct *handle, - * ...) - * { - * struct tevent_req *req = NULL; - * struct smb_vfs_call_something_state *state = NULL; - * struct tevent_req *subreq = NULL; - * bool ok; - * - * req = tevent_req_create(mem_ctx, &state, - * struct smb_vfs_call_something_state); - * if (req == NULL) { - * return NULL; - * } - * - * VFS_FIND(something_send); - * state->recv_fn = handle->fns->something_recv_fn; - * - * ok = smb_vfs_ev_glue_push_use(evg, req); - * if (!ok) { - * tevent_req_error(req, EIO); - * return tevent_req_post(req, evg->return_ev); - * } - * - * subreq = handle->fns->something_send_fn(mem_ctx, - * evg->next_glue, - * handle, - * ...); - * smb_vfs_ev_glue_pop_use(evg); - * - * if (tevent_req_nomem(subreq, req)) { - * return tevent_req_post(req, evg->return_ev); - * } - * tevent_req_set_callback(subreq, smb_vfs_call_something_done, req); - * - * return req; - * } - * - * static void smb_vfs_call_something_done(struct tevent_req *subreq) - * { - * struct tevent_req *req = - * tevent_req_callback_data(subreq, - * struct tevent_req); - * struct smb_vfs_call_something_state *state = - * tevent_req_data(req, - * struct smb_vfs_call_something_state); - * - * state->retval = state->recv_fn(subreq, - * &state->vfs_aio_state, - * ....); - * TALLOC_FREE(subreq); - * - * if (state->retval == -1) { - * tevent_req_error(req, state->vfs_aio_state.error); - * return; - * } - * tevent_req_done(req); - * } - * - * ssize_t smb_vfs_call_something_recv(struct tevent_req *req, - * struct vfs_aio_state *aio_state, - * ....) - * { - * struct smb_vfs_call_something_state *state = - * tevent_req_data(req, - * struct smb_vfs_call_something_state); - * ssize_t retval = state->retval; - * - * if (tevent_req_is_unix_error(req, &aio_state->error)) { - * tevent_req_received(req); - * return -1; - * } - * - * *aio_state = state->vfs_aio_state; - * ... - * - * tevent_req_received(req); - * return retval; - * } - * - * The most important details are these: - * - * 1. smb_vfs_ev_glue_push_use(evg, req): - * - is a no-op if evg->run_ev and evg->return_ev are the same, - * it means that we're already at the correct impersonation - * and don't need any additional work to be done. - * - Otherwise it will call tevent_req_defer_callback(req, evg->return_ev) - * This means that tevent_req_error() and tevent_req_done() - * will just trigger an immediate event on evg->return_ev. - * Therefore the callers callback function will be called - * in the impersonation of evg->return_ev! This is important - * in order to get the impersonation correct on the way back - * through the stack. - * - It will call tevent_context_push_use(evg->run_ev), - * which will start the impersonation to run_ev. - * So the following code run in the correct context. - * 2. handle->fns->something_send_fn(..., evg->next_glue, ...): - * - We're passing evg->next_glue to the next module. - * - Typically evg->next_glue points to evg again. - * - In case evg->run_ev and evg->return_ev are not the same, - * next_glue will have run_ev and return_ev pointing to evg->run_ev. - * So that the switch from evg->run_ev to evg->return_ev - * happens on the correct boundary. - * 3. smb_vfs_ev_glue_pop_use(evg): - * - is a no-op if evg->run_ev and evg->return_ev are the same, - * it means that we're already at the correct impersonation - * and don't need any additional work to be done. - * - It will call tevent_context_pop_use(evg->run_ev), - * which will revert the impersonation done in - * smb_vfs_ev_glue_push_use(). - * 4. smb_vfs_call_something_send(): - * - The is called in the environment of evg->return_ev. - * - So it needs to use tevent_req_post(req, evg->return_ev) - * 5. smb_vfs_call_something_done(): - * - The is called in the environment of evg->run_ev - * 6. smb_vfs_call_something_recv(): - * - The is called in the environment of evg->return_ev again. - * - * - * Here are some more complex examples: - * - * Example 1: only user_evg without switch to root - * - * SMBD: already impersonated user_evg - * evg'1 = smb2_req->user_evg - * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send() - * | - * | smb_vfs_ev_glue_push_use(evg'1, r'1); - * | | - * | | # no-op run_ev == return_ev - * | | - * | evg'2 = evg'1->next_glue; - * | r'2 = module1_*_send(evg'2); - * | | - * | | evg'3 = evg'2 - * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send() - * | | | - * | | | smb_vfs_ev_glue_push_use(evg'3, r'3); - * | | | | - * | | | | # no-op run_ev == return_ev - * | | | | - * | | | evg'4 = evg'3->next_glue; - * | | | r'4 = module2_*_send(evg'4); - * | | | | - * | | | | evg'5 = evg'4 - * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send() - * | | | | | - * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5); - * | | | | | | - * | | | | | | # no-op run_ev == return_ev - * | | | | | | - * | | | | | evg'6 = evg'5->next_glue; - * | | | | | r'6 = default_*_send(evg'6); - * | | | | | | - * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6) - * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6) - * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6); - * | | | | | | | - * | | | | | | | pthread_create... - * | | | | | | | - * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6); - * | | | | | | - * | | | | | smb_vfs_ev_glue_pop_use(evg'5); - * | | | | | | - * | | | | | | # no-op run_ev == return_ev - * | | | | | | - * | | | | | tevent_req_set_callback(r'6, smb_vfs_call_*_done, r'5); - * | | | | | - * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4); - * | | | | - * | | | smb_vfs_ev_glue_pop_use(evg'3); - * | | | | - * | | | | # no-op run_ev == return_ev - * | | | | - * | | | tevent_req_set_callback(r'4, smb_vfs_call_*_done, r'3); - * | | | - * | | tevent_req_set_callback(r'3, module1_*_done, r'2); - * | | - * | smb_vfs_ev_glue_pop_use(evg'1); - * | | - * | | # no-op run_ev == return_ev - * | | - * | tevent_req_set_callback(r'2, smb_vfs_call_*_done, r'1); - * | - * tevent_req_set_callback(r'1, smbd_*_done, smb2_req); - * - * Worker thread finished, just one event handler processes - * everything as there's no impersonation change. - * - * tevent_common_invoke_immediate_handler: - * | - * | before_immediate_handler(ev'6); - * | | - * | | change_to_user() - * | | - * | pthreadpool_tevent_job_done(r'7); - * | | - * | | default_*_done(r'7); - * | | | - * | | | pthreadpool_tevent_recv(r'7); - * | | | TALLOC_FREE(r'7); - * | | | tevent_req_done('r6); - * | | | | - * | | | | smb_vfs_call_*_done(r'6); - * | | | | | - * | | | | | default_*_recv(r'6); - * | | | | | TALLOC_FREE(r'6) - * | | | | | tevent_req_done(r'5); - * | | | | | | - * | | | | | | module2_*_done(r'5): - * | | | | | | | - * | | | | | | | SMB_VFS_*_recv(r'5); # smb_vfs_call_*_recv() - * | | | | | | | TALLOC_FREE(r'5) - * | | | | | | | tevent_req_done(r'4); - * | | | | | | | | - * | | | | | | | | smb_vfs_call_*_done(r'4); - * | | | | | | | | | - * | | | | | | | | | module2_*_recv(r'4); - * | | | | | | | | | TALLOC_FREE(r'4) - * | | | | | | | | | tevent_req_done(r'3); - * | | | | | | | | | | - * | | | | | | | | | | module1_*_done(r'3): - * | | | | | | | | | | | - * | | | | | | | | | | | SMB_VFS_*_recv(r'3); # smb_vfs_call_*_recv() - * | | | | | | | | | | | TALLOC_FREE(r'3) - * | | | | | | | | | | | tevent_req_done(r'2); - * | | | | | | | | | | | | - * | | | | | | | | | | | | smb_vfs_*_done(r'2); - * | | | | | | | | | | | | | - * | | | | | | | | | | | | | module1_*_recv(r'2); - * | | | | | | | | | | | | | TALLOC_FREE(r'2) - * | | | | | | | | | | | | | tevent_req_done(r'1); - * | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | smbd_*_done(r'1); - * | | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | | SMB_VFS_*_recv(r'1); # smb_vfs_call_*_recv() - * | | | | | | | | | | | | | | | TALLOC_FREE(r'1) - * | | | | | | | | | | | | | | | smbd_response_to_client() - * | | | | | | | | | | | | | | | return - * | | | | | | | | | | | | | | | - * | | | | | | | | | | | | | | return - * | | | | | | | | | | | | | | - * | | | | | | | | | | | | | return - * | | | | | | | | | | | | | - * | | | | | | | | | | | | return - * | | | | | | | | | | | | - * | | | | | | | | | | | return - * | | | | | | | | | | | - * | | | | | | | | | | return - * | | | | | | | | | | - * | | | | | | | | | return - * | | | | | | | | | - * | | | | | | | | return - * | | | | | | | | - * | | | | | | | return - * | | | | | | | - * | | | | | | return - * | | | | | | - * | | | | | return - * | | | | | - * | | | | return - * | | | | - * | | | return - * | | | - * | | return - * | | - * | after_immediate_handler(ev'6); - * | | - * | | # lazy no change_to_user() - * | | - * | return - * - * - * Example 2: start with user_evg and let module1 switch to root - * - * SMBD: already impersonated user_evg - * evg'1 = smb2_req->user_evg - * r'1 = SMB_VFS_*_SEND(evg'1); # smb_vfs_call_*_send() - * | - * | smb_vfs_ev_glue_push_use(evg'1, r'1); - * | | - * | | # no-op run_ev == return_ev - * | | - * | evg'2 = evg'1->next_glue; - * | r'2 = module1_*_send(evg'2); - * | | - * | | evg'3 = smb_vfs_ev_glue_get_root_glue(evg'2) - * | | r'3 = SMB_VFS_*_NEXT_SEND(evg'3); # smb_vfs_call_*_send() - * | | | - * | | | smb_vfs_ev_glue_push_use(evg'3, r'3); - * | | | | - * | | | | tevent_req_defer_callback(r'3, evg'3->return_ev); - * | | | | tevent_context_push_use(evg'3->run_ev) - * | | | | | - * | | | | | become_root() - * | | | | | - * | | | | - * | | | evg'4 = evg'3->next_glue; - * | | | r'4 = module2_*_send(evg'4); - * | | | | - * | | | | evg'5 = smb_vfs_ev_glue_get_root_glue(evg'4) - * | | | | r'5 = SMB_VFS_*_NEXT_SEND(evg'5); # smb_vfs_call_*_send() - * | | | | | - * | | | | | smb_vfs_ev_glue_push_use(evg'5, r'5); - * | | | | | | - * | | | | | | # no-op run_ev == return_ev, already root - * | | | | | | - * | | | | | evg'6 = evg'5->next_glue; - * | | | | | r'6 = default_*_send(evg'6); - * | | | | | | - * | | | | | | ev'6 = smb_vfs_ev_glue_ev_ctx(evg'6) - * | | | | | | tp'6 = smb_vfs_ev_glue_tp_chdir_safe(evg'6) - * | | | | | | r'7 = pthreadpool_tevent_send(ev'6, tp'6); - * | | | | | | | - * | | | | | | | pthread_create... - * | | | | | | | - * | | | | | | tevent_req_set_callback(r'7, default_*_done, r'6); - * | | | | | | - * | | | | | smb_vfs_ev_glue_pop_use(evg'5); - * | | | | | | - * | | | | | | # no-op run_ev == return_ev, still stay as root - * | | | | | | - * | | | | | tevent_req_set_callback(r'6, smb_vfs_*_done, r'5); - * | | | | | - * | | | | tevent_req_set_callback(r'5, module2_*_done, r'4); - * | | | | - * | | | smb_vfs_ev_glue_pop_use(evg'3); - * | | | | - * | | | | tevent_context_pop_use(evg'3->run_ev) - * | | | | | - * | | | | | unbecome_root() - * | | | | - * | | | tevent_req_set_callback(r'4, smb_vfs_*_done, r'3); - * | | | - * | | tevent_req_set_callback(r'3, module1_*_done, r'2); - * | | - * | smb_vfs_ev_glue_pop_use(evg'1); - * | | - * | | # no-op run_ev == return_ev - * | | - * | tevent_req_set_callback(r'2, smb_vfs_*_done, r'1); - * | - * tevent_req_set_callback(r'1, smbd_*_done, smb2_req); - * - * Worker thread finished, just one event handler processes - * everything as there's no impersonation change. - * - * tevent_common_invoke_immediate_handler: - * | - * | before_immediate_handler(ev'6); - * | | - * | | become_root() - * | | - * | pthreadpool_tevent_job_done(r'7); - * | | - * | | default_*_done(r'7); - * | | | - * | | | pthreadpool_tevent_recv(r'7); - * | | | TALLOC_FREE(r'7); - * | | | tevent_req_done('r6); - * | | | | - * | | | | smb_vfs_*_done(r'6); - * | | | | | - * | | | | | default_*_recv(r'6); - * | | | | | TALLOC_FREE(r'6) - * | | | | | tevent_req_done(r'5); - * | | | | | | - * | | | | | | module2_*_done(r'5): - * | | | | | | | - * | | | | | | | SMB_VFS_*_recv(r'5); - * | | | | | | | TALLOC_FREE(r'5) - * | | | | | | | tevent_req_done(r'4); - * | | | | | | | | - * | | | | | | | | smb_vfs_*_done(r'4); - * | | | | | | | | | - * | | | | | | | | | module2_*_recv(r'4); - * | | | | | | | | | TALLOC_FREE(r'4) - * | | | | | | | | | tevent_req_done(r'3); - * | | | | | | | | | | return - * | | | | | | | | | | - * | | | | | | | | | return - * | | | | | | | | | - * | | | | | | | | return - * | | | | | | | | - * | | | | | | | return - * | | | | | | | - * | | | | | | return - * | | | | | | - * | | | | | return - * | | | | | - * | | | | return - * | | | | - * | | | return - * | | | - * | | return - * | | - * | | - * | after_immediate_handler(ev'6); - * | | - * | | unbecome_root() - * | | - * | return - * | - * tevent_common_invoke_immediate_handler: - * | - * | before_immediate_handler(ev'6); - * | | - * | | change_to_user() - * | | - * | tevent_req_trigger(); - * | ... - * | _tevent_req_notify_callback(r'3) - * | | - * | | module1_*_done(r'3): - * | | | - * | | | SMB_VFS_*_recv(r'3); - * | | | TALLOC_FREE(r'3) - * | | | tevent_req_done(r'2); - * | | | | - * | | | | smb_vfs_*_done(r'2); - * | | | | | - * | | | | | module1_*_recv(r'2); - * | | | | | TALLOC_FREE(r'2) - * | | | | | tevent_req_done(r'1); - * | | | | | | - * | | | | | | smbd_*_done(r'1); - * | | | | | | | - * | | | | | | | SMB_VFS_*_recv(r'1); - * | | | | | | | TALLOC_FREE(r'1) - * | | | | | | | smbd_response_to_client() - * | | | | | | | return - * | | | | | | | - * | | | | | | return - * | | | | | | - * | | | | | return - * | | | | | - * | | | | return - * | | | | - * | | | return - * | | | - * | | return - * | | - * | after_immediate_handler(ev'6); - * | | - * | | # lazy no change_to_user() - * | | - * | return - * - */ -struct smb_vfs_ev_glue { - /* - * The event context that should be used - * to report the result back. - * - * The is basically the callers context. - */ - struct tevent_context *return_ev; - - /* - * The event context and threadpool wrappers - * the current context should use. - * - * tp_fd_safe only allows fd based functions - * which don't require impersonation, this - * is basically the raw threadpool. - * - * tp_path_safe allows path based functions - * to be called under the correct impersonation. - * But chdir/fchdir is not allowed! - * Typically calls like openat() or other *at() - * syscalls. - * - * tp_chdir_safe is like path_safe, but also - * allows chdir/fchdir to be called, the job - * can safely return with a changed directory, - * the threadpool wrapper takes care of - * a cleanup if required. - * This is needed if *at() syscalls need - * to be simulated by fchdir();$syscall(), - * e.g. getxattr(). - * - * The distinction between these threadpool - * is required because of OS limitations - * (as of 2018): - * - only Linux supports per thread - * credentials (seteuid....) - * - only Linux supports a per thread - * current working directory, - * using unshare(CLONE_FS). But - * in some constrained container - * environments even that is not available - * on Linux. - * - * tp_fd_safe is typically the raw threadpool - * without a wrapper. - * - * On Linux tp_path_safe and tp_chdir_safe - * are typically the same (if unshare(CLONE_FS) is available) - * they're implemented as wrappers of the raw threadpool. - * - * On other OSes tp_path_safe is a wrapper - * arround a sync threadpool (without real threads, just blocking - * the main thread), but hidden behind the pthreadpool_tevent - * api in order to make the restriction transparent. - * - * On other OSes tp_chdir_safe is a wrapper - * arround a sync threadpool (without real threads, just blocking - * the main thread), but hidden behind the pthreadpool_tevent - * api in order to make the restriction transparent. - * It just remembers/restores the current working directory, - * typically using open(".", O_RDONLY | O_DIRECTORY) and fchdir(). - */ - struct tevent_context *run_ev; - struct pthreadpool_tevent *run_tp_fd_safe; - struct pthreadpool_tevent *run_tp_path_safe; - struct pthreadpool_tevent *run_tp_chdir_safe; - - /* - * The glue that should be passed down - * to sub request in the stack. - * - * Typically this points to itself. - * - * But smb_vfs_ev_glue_create_switch() allows - * to create context that can switch - * between two user glues. - */ - const struct smb_vfs_ev_glue *next_glue; - - /* - * If some code path wants to run - * some constraint code as root, - * basically an async version of become_root() - * and unbecome_root(). - * - * The caller can call smb_vfs_ev_glue_get_root_glue() - * to get a root glue that can be passed - * to the SMB_VFS_*_SEND() function that - * should run as root. - * - * Note that the callback (registered with - * tevent_req_set_callback()) won't run as - * root anymore! - */ - const struct smb_vfs_ev_glue *root_glue; -}; - -static struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_internal( - TALLOC_CTX *mem_ctx, - struct tevent_context *return_ev, - struct tevent_context *run_ev, - struct pthreadpool_tevent *run_tp_fd_safe, - struct pthreadpool_tevent *run_tp_path_safe, - struct pthreadpool_tevent *run_tp_chdir_safe) -{ - struct smb_vfs_ev_glue *evg = NULL; - - evg = talloc_zero(mem_ctx, struct smb_vfs_ev_glue); - if (evg == NULL) { - return NULL; - } - *evg = (struct smb_vfs_ev_glue) { - .return_ev = return_ev, - .run_ev = run_ev, - .run_tp_fd_safe = run_tp_fd_safe, - .run_tp_path_safe = run_tp_path_safe, - .run_tp_chdir_safe = run_tp_chdir_safe, - .next_glue = evg, - }; - - return evg; -} - -struct tevent_context *smb_vfs_ev_glue_ev_ctx(const struct smb_vfs_ev_glue *evg) -{ - return evg->run_ev; -} - -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_fd_safe(const struct smb_vfs_ev_glue *evg) -{ - return evg->run_tp_fd_safe; -} - -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_path_safe(const struct smb_vfs_ev_glue *evg) -{ - return evg->run_tp_path_safe; -} - -struct pthreadpool_tevent *smb_vfs_ev_glue_tp_chdir_safe(const struct smb_vfs_ev_glue *evg) -{ - return evg->run_tp_chdir_safe; -} - -const struct smb_vfs_ev_glue *smb_vfs_ev_glue_get_root_glue(const struct smb_vfs_ev_glue *evg) -{ - return evg->root_glue; -} - -struct smb_vfs_ev_glue *smb_vfs_ev_glue_create(TALLOC_CTX *mem_ctx, - struct tevent_context *user_ev, - struct pthreadpool_tevent *user_tp_fd_safe, - struct pthreadpool_tevent *user_tp_path_safe, - struct pthreadpool_tevent *user_tp_chdir_safe, - struct tevent_context *root_ev, - struct pthreadpool_tevent *root_tp_fd_safe, - struct pthreadpool_tevent *root_tp_path_safe, - struct pthreadpool_tevent *root_tp_chdir_safe) -{ - struct smb_vfs_ev_glue *evg_uu = NULL; - struct smb_vfs_ev_glue *evg_ru = NULL; - struct smb_vfs_ev_glue *evg_rr = NULL; - - /* - * The top level glue (directly returned from this function). - * - * It uses user_ev and user_tp_* only. - */ - evg_uu = smb_vfs_ev_glue_create_internal(mem_ctx, - user_ev, /* return_ev */ - user_ev, /* run_ev */ - user_tp_fd_safe, - user_tp_path_safe, - user_tp_chdir_safe); - if (evg_uu == NULL) { - return NULL; - } - - /* - * The first root glue (returned by smb_vfs_ev_glue_get_root_glue()). - * - * It uses root_ev and root_tp, but user_ev as return ev, - * which means that the caller's callback (registered with - * tevent_req_set_callback()) will run as user_ev. - */ - evg_ru = smb_vfs_ev_glue_create_internal(evg_uu, - user_ev, /* return_ev */ - root_ev, /* run_ev */ - root_tp_fd_safe, - root_tp_path_safe, - root_tp_chdir_safe); - if (evg_ru == NULL) { - TALLOC_FREE(evg_uu); - return NULL; - } - - /* - * The second root glue (returned by smb_vfs_ev_glue_get_root_glue() on - * root glue itself. This means code can always call - * smb_vfs_ev_glue_get_root_glue() and don't have to care if the - * passed glue is already a root glue. - * - * This will then recursively point to its own root_glue pointer. - * - * It only uses root_ev and root_tp. - */ - evg_rr = smb_vfs_ev_glue_create_internal(evg_ru, - root_ev, /* return_ev */ - root_ev, /* run_ev */ - root_tp_fd_safe, - root_tp_path_safe, - root_tp_chdir_safe); - if (evg_rr == NULL) { - TALLOC_FREE(evg_uu); - return NULL; - } - - /* - * We now setup the glue hierarchy. - * - * Search for "Design of the smb_vfs_ev_glue infrastructure" above - * for a detailed description how the chain works. - * - * "Example 2: start with user_evg and let module1 switch to root" - * explains it for the root_glue chaining. - */ - evg_rr->root_glue = evg_rr; - evg_ru->root_glue = evg_rr; - evg_uu->root_glue = evg_ru; - - /* - * As evg_ru is a boundary with - * run_ev != return_ev, we need to - * alter its next_glue. - */ - evg_ru->next_glue = evg_rr; - - return evg_uu; -} - -/* - * This can be used to create a temporary glue - * if you need to switch between two user contexts - * - * It's the caller's duty to make sure both - * glues stay alive for the lifetime of the - * created switch. - */ -struct smb_vfs_ev_glue *smb_vfs_ev_glue_create_switch( - TALLOC_CTX *mem_ctx, - const struct smb_vfs_ev_glue *return_evg, - const struct smb_vfs_ev_glue *run_evg) -{ - const struct smb_vfs_ev_glue *run_root = run_evg->root_glue; - struct smb_vfs_ev_glue *evg_u = NULL; - struct smb_vfs_ev_glue *evg_r = NULL; - - /* - * Here we basically need to dup run_evg (and run_evg->root_glue) - * and replace their return_ev with return_evg->return_ev. - * - * We need to put the new evgs in front of the chain... - */ - evg_u = smb_vfs_ev_glue_create_internal(mem_ctx, - return_evg->return_ev, - run_evg->run_ev, - run_evg->run_tp_fd_safe, - run_evg->run_tp_path_safe, - run_evg->run_tp_chdir_safe); - if (evg_u == NULL) { - return NULL; - } - - evg_r = smb_vfs_ev_glue_create_internal(evg_u, - return_evg->return_ev, - run_root->run_ev, - run_root->run_tp_fd_safe, - run_root->run_tp_path_safe, - run_root->run_tp_chdir_safe); - if (evg_r == NULL) { - return NULL; - } - - /* - * evg_r is a boundary with run_ev != return_ev. - * As run_root is also a boundary, we need to - * use run_root->next_glue in order to get - * a glue that stays as root. - * - * The same applies to the chaining of root - * glues. - */ - evg_r->next_glue = run_root->next_glue; - evg_r->root_glue = run_root->root_glue; - - /* - * evg_r is a boundary with run_ev != return_ev. - * But run_evg is typically not a boundary, - * we use it directly as next_glue. - * - * And the root_glue is the one we constructed above. - */ - evg_u->next_glue = run_evg; - evg_u->root_glue = evg_r; - - return evg_u; -} - int smb_vfs_call_connect(struct vfs_handle_struct *handle, const char *service, const char *user) {