Revert "s3: vfs: add user_vfs_evg to connection_struct"
[samba.git] / source3 / smbd / msdfs.c
index aeae02ed7887497d283bcd967d2e178b6d403a2b..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
@@ -240,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,
@@ -252,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);
@@ -301,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);
 
        /*
@@ -353,97 +407,16 @@ static NTSTATUS create_conn_struct_as_root(TALLOC_CTX *ctx,
                return NT_STATUS_UNSUCCESSFUL;
        }
 
-       conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
-       *pconn = conn;
-
-       return NT_STATUS_OK;
-}
-
-/********************************************************
- 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.
-*********************************************************/
-
-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)
-{
-       NTSTATUS status;
-       become_root();
-       status = create_conn_struct_as_root(ctx, ev,
-                                           msg, pconn,
-                                           snum, path,
-                                           session_info);
-       unbecome_root();
-
-       return status;
-}
-
-/********************************************************
- 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.
-*********************************************************/
-
-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,
-                               struct smb_filename **poldcwd_fname)
-{
-       connection_struct *conn;
-       struct smb_filename *oldcwd_fname = NULL;
-       struct smb_filename smb_fname_connectpath = {0};
-
-       NTSTATUS status = create_conn_struct(ctx, ev,
-                                            msg, &conn,
-                                            snum, path,
-                                            session_info);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       /*
-        * Windows seems to insist on doing trans2getdfsreferral() calls on
-        * the IPC$ share as the anonymous user. If we try to chdir as that
-        * user we will fail.... WTF ? JRA.
-        */
-
-       oldcwd_fname = vfs_GetWd(ctx, conn);
-       if (oldcwd_fname == NULL) {
-               status = map_nt_error_from_unix(errno);
-               DEBUG(3, ("vfs_GetWd failed: %s\n", strerror(errno)));
-               conn_free(conn);
-               return status;
-       }
-
-       smb_fname_connectpath = (struct smb_filename) {
-               .base_name = conn->connectpath
-       };
-
-       if (vfs_ChDir(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) ));
-               TALLOC_FREE(oldcwd_fname);
+       talloc_free(conn->origpath);
+       conn->origpath = talloc_strdup(conn, conn->connectpath);
+       if (conn->origpath == NULL) {
                conn_free(conn);
-               return status;
+               return NT_STATUS_NO_MEMORY;
        }
 
-       *pconn = conn;
-       *poldcwd_fname = oldcwd_fname;
+       conn->fs_capabilities = SMB_VFS_FS_CAPABILITIES(conn, &conn->ts_res);
+       conn->tcon_done = true;
+       *pconn = talloc_move(ctx, &conn);
 
        return NT_STATUS_OK;
 }
@@ -476,7 +449,6 @@ NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
                                struct conn_struct_tos **_c)
 {
        struct conn_struct_tos *c = NULL;
-       struct tevent_context *ev = NULL;
        NTSTATUS status;
 
        *_c = NULL;
@@ -486,24 +458,18 @@ NTSTATUS create_conn_struct_tos(struct messaging_context *msg,
                return NT_STATUS_NO_MEMORY;
        }
 
-       ev = samba_tevent_context_init(c);
-       if (ev == NULL) {
-               TALLOC_FREE(c);
-               return NT_STATUS_NO_MEMORY;
-       }
-
-       status = create_conn_struct(c,
-                                   ev,
-                                   msg,
-                                   &c->conn,
-                                   snum,
-                                   path,
-                                   session_info);
+       become_root();
+       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;
        }
-       talloc_steal(c, c->conn);
 
        talloc_set_destructor(c, conn_struct_tos_destructor);
 
@@ -1082,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);
-       struct smb_filename *oldcwd_fname = NULL;
+       struct dfs_path *pdp = talloc_zero(frame, struct dfs_path);
 
        if (!pdp) {
+               TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
 
@@ -1099,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;
        }
 
@@ -1114,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;
                }
        }
@@ -1131,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;
        }
 
@@ -1149,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,
@@ -1162,38 +1133,34 @@ 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,
-                                       &oldcwd_fname);
+       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
@@ -1205,7 +1172,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                conn->sconn->remote_address =
                        tsocket_address_copy(remote_address, conn->sconn);
                if (conn->sconn->remote_address == NULL) {
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
        }
@@ -1213,7 +1180,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
                conn->sconn->local_address =
                        tsocket_address_copy(local_address, conn->sconn);
                if (conn->sconn->local_address == NULL) {
-                       TALLOC_FREE(pdp);
+                       TALLOC_FREE(frame);
                        return NT_STATUS_NO_MEMORY;
                }
        }
@@ -1255,11 +1222,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx,
 
        status = NT_STATUS_OK;
  err_exit:
-       vfs_ChDir(conn, oldcwd_fname);
-       TALLOC_FREE(oldcwd_fname);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
-       TALLOC_FREE(pdp);
+       TALLOC_FREE(frame);
        return status;
 }
 
@@ -1389,40 +1352,38 @@ 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,
-                                  struct smb_filename **oldpath_fname)
+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_fname);
+       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_fname);
-               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;
 }
 
@@ -1430,15 +1391,16 @@ bool create_msdfs_link(const struct junction_map *jucn)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        char *path = NULL;
-       struct smb_filename *cwd_fname = NULL;
        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_fname)) {
+       ok = junction_to_local_path_tos(jucn, &path, &conn);
+       if (!ok) {
                TALLOC_FREE(frame);
                return False;
        }
@@ -1508,9 +1470,6 @@ bool create_msdfs_link(const struct junction_map *jucn)
        ret = True;
 
 out:
-       vfs_ChDir(conn, cwd_fname);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
        TALLOC_FREE(frame);
        return ret;
 }
@@ -1519,12 +1478,13 @@ bool remove_msdfs_link(const struct junction_map *jucn)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        char *path = NULL;
-       struct smb_filename *cwd_fname = NULL;
        connection_struct *conn;
        bool ret = False;
        struct smb_filename *smb_fname;
+       bool ok;
 
-       if (!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) {
+       ok = junction_to_local_path_tos(jucn, &path, &conn);
+       if (!ok) {
                TALLOC_FREE(frame);
                return false;
        }
@@ -1544,9 +1504,6 @@ bool remove_msdfs_link(const struct junction_map *jucn)
                ret = True;
        }
 
-       vfs_ChDir(conn, cwd_fname);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
        TALLOC_FREE(frame);
        return ret;
 }
@@ -1557,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;
-       struct smb_filename *cwd_fname = NULL;
        struct smb_filename *smb_fname = NULL;
 
        if(*connect_path == '\0') {
+               TALLOC_FREE(frame);
                return 0;
        }
 
@@ -1576,19 +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_fname);
+       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;
@@ -1598,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,
@@ -1616,7 +1574,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
        while ((dname = vfs_readdirname(conn, dirp, NULL, &talloced))
               != NULL) {
                struct smb_filename *smb_dname =
-                       synthetic_smb_fname(talloc_tos(),
+                       synthetic_smb_fname(frame,
                                        dname,
                                        NULL,
                                        NULL,
@@ -1634,11 +1592,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum)
        SMB_VFS_CLOSEDIR(conn,dirp);
 
 out:
-       TALLOC_FREE(smb_fname);
-       vfs_ChDir(conn, cwd_fname);
-       TALLOC_FREE(cwd_fname);
-       SMB_VFS_DISCONNECT(conn);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return cnt;
 }
 
@@ -1650,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;
-       struct smb_filename *cwd_fname = NULL;
        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;
        }
 
@@ -1675,19 +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_fname);
+       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
@@ -1728,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,
@@ -1795,10 +1751,7 @@ out:
                SMB_VFS_CLOSEDIR(conn,dirp);
        }
 
-       TALLOC_FREE(smb_fname);
-       vfs_ChDir(conn, cwd_fname);
-       TALLOC_FREE(cwd_fname);
-       conn_free(conn);
+       TALLOC_FREE(frame);
        return cnt;
 }