Revert "s3: vfs: add user_vfs_evg to connection_struct"
[samba.git] / source3 / smbd / msdfs.c
index fb222127fd4fbf8f49b8ce7430faae356fdf0f14..9b0b2de27caa199138363811a7631f5d377d39df 100644 (file)
 #include "smbd/globals.h"
 #include "msdfs.h"
 #include "auth.h"
+#include "../auth/auth_util.h"
 #include "lib/param/loadparm.h"
 #include "libcli/security/security.h"
 #include "librpc/gen_ndr/ndr_dfsblobs.h"
+#include "lib/tsocket/tsocket.h"
+#include "lib/pthreadpool/pthreadpool_tevent.h"
 
 /**********************************************************************
  Parse a DFS pathname of the form \hostname\service\reqpath
@@ -239,7 +242,6 @@ static NTSTATUS parse_dfs_path(connection_struct *conn,
 *********************************************************/
 
 static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
-                           struct tevent_context *ev,
                            struct messaging_context *msg,
                            connection_struct **pconn,
                            int snum,
@@ -251,13 +253,40 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
        const char *vfs_user;
        struct smbd_server_connection *sconn;
        const char *servicename = lp_const_servicename(snum);
+       int ret;
 
        sconn = talloc_zero(ctx, struct smbd_server_connection);
        if (sconn == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
 
-       sconn->ev_ctx = ev;
+       sconn->raw_ev_ctx = samba_tevent_context_init(sconn);
+       if (sconn->raw_ev_ctx == NULL) {
+               TALLOC_FREE(sconn);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       sconn->root_ev_ctx = smbd_impersonate_root_create(sconn->raw_ev_ctx);
+       if (sconn->root_ev_ctx == NULL) {
+               TALLOC_FREE(sconn);
+               return NT_STATUS_NO_MEMORY;
+       }
+       sconn->guest_ev_ctx = smbd_impersonate_guest_create(sconn->raw_ev_ctx);
+       if (sconn->guest_ev_ctx == NULL) {
+               TALLOC_FREE(sconn);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /*
+        * We only provide sync threadpools.
+        */
+       ret = pthreadpool_tevent_init(sconn, 0, &sconn->sync_thread_pool);
+       if (ret != 0) {
+               TALLOC_FREE(sconn);
+               return NT_STATUS_NO_MEMORY;
+       }
+       sconn->raw_thread_pool = sconn->sync_thread_pool;
+
        sconn->msg_ctx = msg;
 
        conn = conn_new(sconn);
@@ -300,12 +329,38 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
                        TALLOC_FREE(conn);
                        return NT_STATUS_NO_MEMORY;
                }
-               vfs_user = conn->session_info->unix_info->unix_name;
+               /* unix_info could be NULL in session_info */
+               if (conn->session_info->unix_info != NULL) {
+                       vfs_user = conn->session_info->unix_info->unix_name;
+               } else {
+                       vfs_user = get_current_username();
+               }
        } else {
                /* use current authenticated user in absence of session_info */
                vfs_user = get_current_username();
        }
 
+       /*
+        * The impersonation has to be done by the caller
+        * of create_conn_struct_tos[_cwd]().
+        *
+        * Note: the context can't be changed anyway
+        * as we're using our own tevent_context
+        * and not a global one were other requests
+        * could change the current unix token.
+        *
+        * We just use a wrapper tevent_context in order
+        * to avoid crashes because TALLOC_FREE(conn->user_ev_ctx)
+        * would also remove sconn->raw_ev_ctx.
+        */
+       conn->user_ev_ctx = smbd_impersonate_debug_create(sconn->raw_ev_ctx,
+                                                         "FAKE impersonation",
+                                                         DBGLVL_DEBUG);
+       if (conn->user_ev_ctx == NULL) {
+               TALLOC_FREE(conn);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        set_conn_connectpath(conn, connpath);
 
        /*
@@ -352,62 +407,102 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
+       talloc_free(conn->origpath);
+       conn->origpath = talloc_strdup(conn, conn->connectpath);
+       if (conn->origpath == NULL) {
+               conn_free(conn);
+               return NT_STATUS_NO_MEMORY;
+       }
+
        conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
-       *pconn = conn;
+       conn->tcon_done = true;
+       *pconn = talloc_move(ctx, &conn);
 
        return NT_STATUS_OK;
 }
 
+static int conn_struct_tos_destructor(struct conn_struct_tos *c)
+{
+       if (c->oldcwd_fname != NULL) {
+               vfs_ChDir(c->conn, c->oldcwd_fname);
+               TALLOC_FREE(c->oldcwd_fname);
+       }
+       SMB_VFS_DISCONNECT(c->conn);
+       conn_free(c->conn);
+       return 0;
+}
+
 /********************************************************
  Fake up a connection struct for the VFS layer, for use in
  applications (such as the python bindings), that do not want the
  global working directory changed under them.
 
  SMB_VFS_CONNECT requires root privileges.
-*********************************************************/
+ This temporary uses become_root() and unbecome_root().
 
-NTSTATUS create_conn_struct(TALLOC_CTX *ctx,
-                           struct tevent_context *ev,
-                           struct messaging_context *msg,
-                           connection_struct **pconn,
-                           int snum,
-                           const char *path,
-                           const struct auth_session_info *session_info)
+ But further impersonation has to be cone by the caller.
+*********************************************************/
+NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
+                               int snum,
+                               const char *path,
+                               const struct auth_session_info *session_info,
+                               struct conn_struct_tos **_c)
 {
+       struct conn_struct_tos *c = NULL;
        NTSTATUS status;
+
+       *_c = NULL;
+
+       c = talloc_zero(talloc_tos(), struct conn_struct_tos);
+       if (c == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        become_root();
-       status = create_conn_struct_as_root(ctx, ev,
-                                           msg, pconn,
-                                           snum, path,
+       status = create_conn_struct_as_root(c,
+                                           msg,
+                                           &c->conn,
+                                           snum,
+                                           path,
                                            session_info);
        unbecome_root();
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(c);
+               return status;
+       }
 
-       return status;
+       talloc_set_destructor(c, conn_struct_tos_destructor);
+
+       *_c = c;
+       return NT_STATUS_OK;
 }
 
 /********************************************************
  Fake up a connection struct for the VFS layer.
  Note: this performs a vfs connect and CHANGES CWD !!!! JRA.
 
- The old working directory is returned on *poldcwd, allocated on ctx.
-*********************************************************/
+ See also the comment for create_conn_struct_tos() above!
 
-NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
-                               struct tevent_context *ev,
-                               struct messaging_context *msg,
-                               connection_struct **pconn,
-                               int snum,
-                               const char *path,
-                               const struct auth_session_info *session_info,
-                               char **poldcwd)
+ The CWD change is reverted by the destructor of
+ conn_struct_tos when the current talloc_tos() is destroyed.
+*********************************************************/
+NTSTATUS create_conn_struct_tos_cwd(struct messaging_context *msg,
+                                   int snum,
+                                   const char *path,
+                                   const struct auth_session_info *session_info,
+                                   struct conn_struct_tos **_c)
 {
-       connection_struct *conn;
-       char *oldcwd;
+       struct conn_struct_tos *c = NULL;
+       struct smb_filename smb_fname_connectpath = {0};
+       NTSTATUS status;
+
+       *_c = NULL;
 
-       NTSTATUS status = create_conn_struct(ctx, ev,
-                                            msg, &conn,
-                                            snum, path,
-                                            session_info);
+       status = create_conn_struct_tos(msg,
+                                       snum,
+                                       path,
+                                       session_info,
+                                       &c);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -418,26 +513,29 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx,
         * user we will fail.... WTF ? JRA.
         */
 
-       oldcwd = vfs_GetWd(ctx, conn);
-       if (oldcwd == NULL) {
+       c->oldcwd_fname = vfs_GetWd(c, c->conn);
+       if (c->oldcwd_fname == NULL) {
                status = map_nt_error_from_unix(errno);
                DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
-               conn_free(conn);
+               TALLOC_FREE(c);
                return status;
        }
 
-       if (vfs_ChDir(conn,conn->connectpath) != 0) {
+       smb_fname_connectpath = (struct smb_filename) {
+               .base_name = c->conn->connectpath
+       };
+
+       if (vfs_ChDir(c->conn, &smb_fname_connectpath) != 0) {
                status = map_nt_error_from_unix(errno);
-               DEBUG(3,("create_conn_struct: Can't ChDir to new conn path %s. "
-                       "Error was %s\n",
-                       conn->connectpath, strerror(errno) ));
-               conn_free(conn);
+               DBG_NOTICE("Can't ChDir to new conn path %s. "
+                          "Error was %s\n",
+                          c->conn->connectpath, strerror(errno));
+               TALLOC_FREE(c->oldcwd_fname);
+               TALLOC_FREE(c);
                return status;
        }
 
-       *pconn = conn;
-       *poldcwd = oldcwd;
-
+       *_c = c;
        return NT_STATUS_OK;
 }
 
@@ -566,9 +664,8 @@ static bool parse_msdfs_symlink(TALLOC_CTX *ctx,
 
 static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
                        connection_struct *conn,
-                       const char *path,
-                       char **pp_link_target,
-                       SMB_STRUCT_STAT *sbufp)
+                       struct smb_filename *smb_fname,
+                       char **pp_link_target)
 {
        int referral_len = 0;
 #if defined(HAVE_BROKEN_READLINK)
@@ -578,7 +675,6 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
 #endif
        size_t bufsize = 0;
        char *link_target = NULL;
-       struct smb_filename smb_fname;
 
        if (pp_link_target) {
                bufsize = 1024;
@@ -592,33 +688,28 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
                link_target = link_target_buf;
        }
 
-       ZERO_STRUCT(smb_fname);
-       smb_fname.base_name = discard_const_p(char, path);
-
-       if (SMB_VFS_LSTAT(conn, &smb_fname) != 0) {
+       if (SMB_VFS_LSTAT(conn, smb_fname) != 0) {
                DEBUG(5,("is_msdfs_link_read_target: %s does not exist.\n",
-                       path));
+                       smb_fname->base_name));
                goto err;
        }
-       if (!S_ISLNK(smb_fname.st.st_ex_mode)) {
+       if (!S_ISLNK(smb_fname->st.st_ex_mode)) {
                DEBUG(5,("is_msdfs_link_read_target: %s is not a link.\n",
-                                       path));
+                       smb_fname->base_name));
                goto err;
        }
-       if (sbufp != NULL) {
-               *sbufp = smb_fname.st;
-       }
 
-       referral_len = SMB_VFS_READLINK(conn, path, link_target, bufsize - 1);
+       referral_len = SMB_VFS_READLINK(conn, smb_fname,
+                               link_target, bufsize - 1);
        if (referral_len == -1) {
                DEBUG(0,("is_msdfs_link_read_target: Error reading "
                        "msdfs link %s: %s\n",
-                       path, strerror(errno)));
+                       smb_fname->base_name, strerror(errno)));
                goto err;
        }
        link_target[referral_len] = '\0';
 
-       DEBUG(5,("is_msdfs_link_internal: %s -> %s\n",path,
+       DEBUG(5,("is_msdfs_link_internal: %s -> %s\n", smb_fname->base_name,
                                link_target));
 
        if (!strnequal(link_target, "msdfs:", 6)) {
@@ -639,14 +730,12 @@ static bool is_msdfs_link_internal(TALLOC_CTX *ctx,
 **********************************************************************/
 
 bool is_msdfs_link(connection_struct *conn,
-               const char *path,
-               SMB_STRUCT_STAT *sbufp)
+               struct smb_filename *smb_fname)
 {
        return is_msdfs_link_internal(talloc_tos(),
                                        conn,
-                                       path,
-                                       NULL,
-                                       sbufp);
+                                       smb_fname,
+                                       NULL);
 }
 
 /*****************************************************************
@@ -705,8 +794,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
 
        /* Optimization - check if we can redirect the whole path. */
 
-       if (is_msdfs_link_internal(ctx, conn, smb_fname->base_name,
-                                  pp_targetpath, NULL)) {
+       if (is_msdfs_link_internal(ctx, conn, smb_fname, pp_targetpath)) {
                /* XX_ALLOW_WCARD_XXX is called from search functions. */
                if (ucf_flags &
                                (UCF_COND_ALLOW_WCARD_LCOMP|
@@ -769,8 +857,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx,
                }
 
                if (is_msdfs_link_internal(ctx, conn,
-                                          smb_fname->base_name, pp_targetpath,
-                                          NULL)) {
+                                          smb_fname, pp_targetpath)) {
                        DEBUG(4, ("dfs_path_lookup: Redirecting %s because "
                                  "parent %s is dfs link\n", dfspath,
                                  smb_fname_str_dbg(smb_fname)));
@@ -961,15 +1048,17 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                           int *consumedcntp,
                           bool *self_referralp)
 {
-       struct connection_struct *conn;
+       TALLOC_CTX *frame = talloc_stackframe();
+       struct conn_struct_tos *c = NULL;
+       struct connection_struct *conn = NULL;
        char *targetpath = NULL;
        int snum;
        NTSTATUS status = NT_STATUS_NOT_FOUND;
        bool dummy;
-       struct dfs_path *pdp = talloc(ctx, struct dfs_path);
-       char *oldpath;
+       struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
 
        if (!pdp) {
+               TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -978,13 +1067,14 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
        status = parse_dfs_path(NULL, dfs_path, False, allow_broken_path,
                                pdp, &dummy);
        if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(frame);
                return status;
        }
 
        jucn->service_name = talloc_strdup(ctx, pdp->servicename);
        jucn->volume_name = talloc_strdup(ctx, pdp->reqpath);
        if (!jucn->service_name || !jucn->volume_name) {
-               TALLOC_FREE(pdp);
+               TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -993,15 +1083,17 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
        if(snum < 0) {
                char *service_name = NULL;
                if ((snum = find_service(ctx, jucn->service_name, &service_name)) < 0) {
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NOT_FOUND;
                }
                if (!service_name) {
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
                TALLOC_FREE(jucn->service_name);
                jucn->service_name = talloc_strdup(ctx, service_name);
                if (!jucn->service_name) {
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
        }
@@ -1010,7 +1102,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                DEBUG(3,("get_referred_path: |%s| in dfs path %s is not "
                        "a dfs root.\n",
                        pdp->servicename, dfs_path));
-               TALLOC_FREE(pdp);
+               TALLOC_FREE(frame);
                return NT_STATUS_NOT_FOUND;
        }
 
@@ -1028,7 +1120,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                int refcount;
 
                if (*lp_msdfs_proxy(talloc_tos(), snum) == '\0') {
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return self_ref(ctx,
                                        dfs_path,
                                        jucn,
@@ -1041,35 +1133,57 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                 * the configured target share.
                 */
 
-               tmp = talloc_asprintf(talloc_tos(), "msdfs:%s",
-                                     lp_msdfs_proxy(talloc_tos(), snum));
+               tmp = talloc_asprintf(frame, "msdfs:%s",
+                                     lp_msdfs_proxy(frame, snum));
                if (tmp == NULL) {
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
 
                if (!parse_msdfs_symlink(ctx, snum, tmp, &ref, &refcount)) {
-                       TALLOC_FREE(tmp);
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return NT_STATUS_INVALID_PARAMETER;
                }
-               TALLOC_FREE(tmp);
                jucn->referral_count = refcount;
                jucn->referral_list = ref;
                *consumedcntp = strlen(dfs_path);
-               TALLOC_FREE(pdp);
+               TALLOC_FREE(frame);
                return NT_STATUS_OK;
        }
 
-       status = create_conn_struct_cwd(ctx,
-                                       server_event_context(),
-                                       server_messaging_context(),
-                                       &conn, snum,
-                                       lp_path(talloc_tos(), snum), NULL, &oldpath);
+       status = create_conn_struct_tos_cwd(global_messaging_context(),
+                                           snum,
+                                           lp_path(frame, snum),
+                                           NULL,
+                                           &c);
        if (!NT_STATUS_IS_OK(status)) {
-               TALLOC_FREE(pdp);
+               TALLOC_FREE(frame);
                return status;
        }
+       conn = c->conn;
+
+       /*
+        * TODO
+        *
+        * The remote and local address should be passed down to
+        * create_conn_struct_cwd.
+        */
+       if (conn->sconn->remote_address == NULL) {
+               conn->sconn->remote_address =
+                       tsocket_address_copy(remote_address, conn->sconn);
+               if (conn->sconn->remote_address == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
+       if (conn->sconn->local_address == NULL) {
+               conn->sconn->local_address =
+                       tsocket_address_copy(local_address, conn->sconn);
+               if (conn->sconn->local_address == NULL) {
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
 
        /* If this is a DFS path dfs_lookup should return
         * NT_STATUS_PATH_NOT_COVERED. */
@@ -1108,10 +1222,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
 
        status = NT_STATUS_OK;
  err_exit:
-       vfs_ChDir(conn, oldpath);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
-       TALLOC_FREE(pdp);
+       TALLOC_FREE(frame);
        return status;
 }
 
@@ -1241,51 +1352,56 @@ bool create_junction(TALLOC_CTX *ctx,
  Forms a valid Unix pathname from the junction
  **********************************************************************/
 
-static bool junction_to_local_path(const struct junction_map *jucn,
-                                  char **pp_path_out,
-                                  connection_struct **conn_out,
-                                  char **oldpath)
+static bool junction_to_local_path_tos(const struct junction_map *jucn,
+                                      char **pp_path_out,
+                                      connection_struct **conn_out)
 {
+       struct conn_struct_tos *c = NULL;
        int snum;
+       char *path_out = NULL;
        NTSTATUS status;
 
        snum = lp_servicenumber(jucn->service_name);
        if(snum < 0) {
                return False;
        }
-       status = create_conn_struct_cwd(talloc_tos(),
-                                       server_event_context(),
-                                       server_messaging_context(),
-                                       conn_out,
-                                       snum, lp_path(talloc_tos(), snum), NULL, oldpath);
+       status = create_conn_struct_tos_cwd(global_messaging_context(),
+                                           snum,
+                                           lp_path(talloc_tos(), snum),
+                                           NULL,
+                                           &c);
        if (!NT_STATUS_IS_OK(status)) {
                return False;
        }
 
-       *pp_path_out = talloc_asprintf(*conn_out,
+       path_out = talloc_asprintf(c,
                        "%s/%s",
                        lp_path(talloc_tos(), snum),
                        jucn->volume_name);
-       if (!*pp_path_out) {
-               vfs_ChDir(*conn_out, *oldpath);
-               SMB_VFS_DISCONNECT(*conn_out);
-               conn_free(*conn_out);
+       if (path_out == NULL) {
+               TALLOC_FREE(c);
                return False;
        }
+       *pp_path_out = path_out;
+       *conn_out = c->conn;
        return True;
 }
 
 bool create_msdfs_link(const struct junction_map *jucn)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        char *path = NULL;
-       char *cwd;
        char *msdfs_link = NULL;
        connection_struct *conn;
        int i=0;
        bool insert_comma = False;
        bool ret = False;
+       struct smb_filename *smb_fname = NULL;
+       bool ok;
 
-       if(!junction_to_local_path(jucn, &path, &conn, &cwd)) {
+       ok = junction_to_local_path_tos(jucn, &path, &conn);
+       if (!ok) {
+               TALLOC_FREE(frame);
                return False;
        }
 
@@ -1326,27 +1442,24 @@ bool create_msdfs_link(const struct junction_map *jucn)
        DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n",
                path, msdfs_link));
 
-       if(SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
-               if (errno == EEXIST) {
-                       struct smb_filename *smb_fname;
-
-                       smb_fname = synthetic_smb_fname(talloc_tos(),
-                                               path,
-                                               NULL,
-                                               NULL,
-                                               0);
-                       if (smb_fname == NULL) {
-                               errno = ENOMEM;
-                               goto out;
-                       }
+       smb_fname = synthetic_smb_fname(frame,
+                               path,
+                               NULL,
+                               NULL,
+                               0);
+       if (smb_fname == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
 
+       if(SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
+               if (errno == EEXIST) {
                        if(SMB_VFS_UNLINK(conn, smb_fname)!=0) {
                                TALLOC_FREE(smb_fname);
                                goto out;
                        }
-                       TALLOC_FREE(smb_fname);
                }
-               if (SMB_VFS_SYMLINK(conn, msdfs_link, path) < 0) {
+               if (SMB_VFS_SYMLINK(conn, msdfs_link, smb_fname) < 0) {
                        DEBUG(1,("create_msdfs_link: symlink failed "
                                 "%s -> %s\nError: %s\n",
                                 path, msdfs_link, strerror(errno)));
@@ -1357,30 +1470,32 @@ bool create_msdfs_link(const struct junction_map *jucn)
        ret = True;
 
 out:
-       vfs_ChDir(conn, cwd);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return ret;
 }
 
 bool remove_msdfs_link(const struct junction_map *jucn)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        char *path = NULL;
-       char *cwd;
        connection_struct *conn;
        bool ret = False;
        struct smb_filename *smb_fname;
+       bool ok;
 
-       if (!junction_to_local_path(jucn, &path, &conn, &cwd)) {
+       ok = junction_to_local_path_tos(jucn, &path, &conn);
+       if (!ok) {
+               TALLOC_FREE(frame);
                return false;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(),
+       smb_fname = synthetic_smb_fname(frame,
                                        path,
                                        NULL,
                                        NULL,
                                        0);
        if (smb_fname == NULL) {
+               TALLOC_FREE(frame);
                errno = ENOMEM;
                return false;
        }
@@ -1389,10 +1504,7 @@ bool remove_msdfs_link(const struct junction_map *jucn)
                ret = True;
        }
 
-       TALLOC_FREE(smb_fname);
-       vfs_ChDir(conn, cwd);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return ret;
 }
 
@@ -1402,18 +1514,20 @@ bool remove_msdfs_link(const struct junction_map *jucn)
 
 static int count_dfs_links(TALLOC_CTX *ctx, int snum)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        size_t cnt = 0;
        DIR *dirp = NULL;
        const char *dname = NULL;
        char *talloced = NULL;
-       const char *connect_path = lp_path(talloc_tos(), snum);
-       const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
-       connection_struct *conn;
+       const char *connect_path = lp_path(frame, snum);
+       const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
+       struct conn_struct_tos *c = NULL;
+       connection_struct *conn = NULL;
        NTSTATUS status;
-       char *cwd;
        struct smb_filename *smb_fname = NULL;
 
        if(*connect_path == '\0') {
+               TALLOC_FREE(frame);
                return 0;
        }
 
@@ -1421,16 +1535,18 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
         * Fake up a connection struct for the VFS layer.
         */
 
-       status = create_conn_struct_cwd(talloc_tos(),
-                                       server_event_context(),
-                                       server_messaging_context(),
-                                       &conn,
-                                       snum, connect_path, NULL, &cwd);
+       status = create_conn_struct_tos_cwd(global_messaging_context(),
+                                           snum,
+                                           connect_path,
+                                           NULL,
+                                           &c);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3, ("create_conn_struct failed: %s\n",
                          nt_errstr(status)));
+               TALLOC_FREE(frame);
                return 0;
        }
+       conn = c->conn;
 
        /* Count a link for the msdfs root - convention */
        cnt = 1;
@@ -1440,7 +1556,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
                goto out;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(),
+       smb_fname = synthetic_smb_fname(frame,
                                        ".",
                                        NULL,
                                        NULL,
@@ -1457,21 +1573,26 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
 
        while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
               != NULL) {
-               if (is_msdfs_link(conn,
-                               dname,
-                               NULL)) {
+               struct smb_filename *smb_dname =
+                       synthetic_smb_fname(frame,
+                                       dname,
+                                       NULL,
+                                       NULL,
+                                       0);
+               if (smb_dname == NULL) {
+                       goto out;
+               }
+               if (is_msdfs_link(conn, smb_dname)) {
                        cnt++;
                }
                TALLOC_FREE(talloced);
+               TALLOC_FREE(smb_dname);
        }
 
        SMB_VFS_CLOSEDIR(conn,dirp);
 
 out:
-       TALLOC_FREE(smb_fname);
-       vfs_ChDir(conn, cwd);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return cnt;
 }
 
@@ -1483,24 +1604,27 @@ static int form_junctions(TALLOC_CTX *ctx,
                                struct junction_map *jucn,
                                size_t jn_remain)
 {
+       TALLOC_CTX *frame = talloc_stackframe();
        size_t cnt = 0;
        DIR *dirp = NULL;
        const char *dname = NULL;
        char *talloced = NULL;
-       const char *connect_path = lp_path(talloc_tos(), snum);
-       char *service_name = lp_servicename(talloc_tos(), snum);
-       const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum);
-       connection_struct *conn;
+       const char *connect_path = lp_path(frame, snum);
+       char *service_name = lp_servicename(frame, snum);
+       const char *msdfs_proxy = lp_msdfs_proxy(frame, snum);
+       struct conn_struct_tos *c = NULL;
+       connection_struct *conn = NULL;
        struct referral *ref = NULL;
-       char *cwd;
        struct smb_filename *smb_fname = NULL;
        NTSTATUS status;
 
        if (jn_remain == 0) {
+               TALLOC_FREE(frame);
                return 0;
        }
 
        if(*connect_path == '\0') {
+               TALLOC_FREE(frame);
                return 0;
        }
 
@@ -1508,16 +1632,18 @@ static int form_junctions(TALLOC_CTX *ctx,
         * Fake up a connection struct for the VFS layer.
         */
 
-       status = create_conn_struct_cwd(ctx,
-                                       server_event_context(),
-                                       server_messaging_context(),
-                                       &conn, snum, connect_path, NULL,
-                                       &cwd);
+       status = create_conn_struct_tos_cwd(global_messaging_context(),
+                                           snum,
+                                           connect_path,
+                                           NULL,
+                                           &c);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3, ("create_conn_struct failed: %s\n",
                          nt_errstr(status)));
+               TALLOC_FREE(frame);
                return 0;
        }
+       conn = c->conn;
 
        /* form a junction for the msdfs root - convention
           DO NOT REMOVE THIS: NT clients will not work with us
@@ -1558,7 +1684,7 @@ static int form_junctions(TALLOC_CTX *ctx,
                goto out;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(),
+       smb_fname = synthetic_smb_fname(frame,
                                        ".",
                                        NULL,
                                        NULL,
@@ -1576,16 +1702,26 @@ static int form_junctions(TALLOC_CTX *ctx,
        while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
               != NULL) {
                char *link_target = NULL;
+               struct smb_filename *smb_dname = NULL;
+
                if (cnt >= jn_remain) {
                        DEBUG(2, ("form_junctions: ran out of MSDFS "
                                "junction slots"));
                        TALLOC_FREE(talloced);
                        goto out;
                }
+               smb_dname = synthetic_smb_fname(talloc_tos(),
+                               dname,
+                               NULL,
+                               NULL,
+                               0);
+               if (smb_dname == NULL) {
+                       TALLOC_FREE(talloced);
+                       goto out;
+               }
                if (is_msdfs_link_internal(ctx,
                                        conn,
-                                       dname, &link_target,
-                                       NULL)) {
+                                       smb_dname, &link_target)) {
                        if (parse_msdfs_symlink(ctx, snum,
                                        link_target,
                                        &jucn[cnt].referral_list,
@@ -1606,6 +1742,7 @@ static int form_junctions(TALLOC_CTX *ctx,
                        TALLOC_FREE(link_target);
                }
                TALLOC_FREE(talloced);
+               TALLOC_FREE(smb_dname);
        }
 
 out:
@@ -1614,9 +1751,7 @@ out:
                SMB_VFS_CLOSEDIR(conn,dirp);
        }
 
-       TALLOC_FREE(smb_fname);
-       vfs_ChDir(conn, cwd);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return cnt;
 }