From 8b4a38b4c94bb3617d0b6444125d9e24f41891cf Mon Sep 17 00:00:00 2001 From: Jeremy Allison <jra@samba.org> Date: Thu, 3 Mar 2016 14:34:57 -0800 Subject: [PATCH] VFS: Modify lchown to take a const struct smb_filename * instead of const char * Preparing to reduce use of lp_posix_pathnames(). Signed-off-by: Jeremy Allison <jra@samba.org> Reviewed-by: Ralph Boehme <slow@samba.org> --- examples/VFS/skel_opaque.c | 6 +++-- examples/VFS/skel_transparent.c | 8 +++--- source3/include/vfs.h | 13 ++++++--- source3/include/vfs_macros.h | 8 +++--- source3/modules/vfs_cap.c | 28 +++++++++++++++++--- source3/modules/vfs_catia.c | 25 ++++++++++++++---- source3/modules/vfs_ceph.c | 14 +++++++--- source3/modules/vfs_default.c | 7 +++-- source3/modules/vfs_fake_acls.c | 19 ++++++++++--- source3/modules/vfs_full_audit.c | 8 +++--- source3/modules/vfs_glusterfs.c | 6 +++-- source3/modules/vfs_media_harmony.c | 25 ++++++++---------- source3/modules/vfs_netatalk.c | 11 ++++---- source3/modules/vfs_time_audit.c | 10 ++++--- source3/modules/vfs_unityed_media.c | 22 +++++++++------- source3/smbd/open.c | 6 +++-- source3/smbd/trans2.c | 4 +-- source3/smbd/vfs.c | 41 ++++++++++++++++++++--------- 18 files changed, 178 insertions(+), 83 deletions(-) diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index 57f5b0921f0..457881dc8be 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -398,8 +398,10 @@ static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp, return -1; } -static int skel_lchown(vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) +static int skel_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { errno = ENOSYS; return -1; diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index d320da95118..55b1ed60c62 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -502,10 +502,12 @@ static int skel_fchown(vfs_handle_struct *handle, files_struct *fsp, return SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid); } -static int skel_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, - gid_t gid) +static int skel_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { - return SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); + return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); } static int skel_chdir(vfs_handle_struct *handle, const char *path) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index 4b3ac0372ad..e77d702d742 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -186,6 +186,8 @@ const struct smb_filename * */ /* Version 35 - Change chown from const char *, to const struct smb_filename * */ +/* Version 35 - Change lchown from const char *, to + const struct smb_filename * */ #define SMB_VFS_INTERFACE_VERSION 35 @@ -653,7 +655,10 @@ struct vfs_fn_pointers { uid_t uid, gid_t gid); int (*fchown_fn)(struct vfs_handle_struct *handle, struct files_struct *fsp, uid_t uid, gid_t gid); - int (*lchown_fn)(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid); + int (*lchown_fn)(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid); int (*chdir_fn)(struct vfs_handle_struct *handle, const char *path); char *(*getwd_fn)(struct vfs_handle_struct *handle); int (*ntimes_fn)(struct vfs_handle_struct *handle, @@ -1106,8 +1111,10 @@ int smb_vfs_call_chown(struct vfs_handle_struct *handle, gid_t gid); int smb_vfs_call_fchown(struct vfs_handle_struct *handle, struct files_struct *fsp, uid_t uid, gid_t gid); -int smb_vfs_call_lchown(struct vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid); +int smb_vfs_call_lchown(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid); int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path); char *smb_vfs_call_getwd(struct vfs_handle_struct *handle); int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 5fbd779c0a5..ae2ba1b797f 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -261,10 +261,10 @@ #define SMB_VFS_NEXT_FCHOWN(handle, fsp, uid, gid) \ smb_vfs_call_fchown((handle)->next, (fsp), (uid), (gid)) -#define SMB_VFS_LCHOWN(conn, path, uid, gid) \ - smb_vfs_call_lchown((conn)->vfs_handles, (path), (uid), (gid)) -#define SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid) \ - smb_vfs_call_lchown((handle)->next, (path), (uid), (gid)) +#define SMB_VFS_LCHOWN(conn, smb_fname, uid, gid) \ + smb_vfs_call_lchown((conn)->vfs_handles, (smb_fname), (uid), (gid)) +#define SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid) \ + smb_vfs_call_lchown((handle)->next, (smb_fname), (uid), (gid)) #define SMB_VFS_CHDIR(conn, path) \ smb_vfs_call_chdir((conn)->vfs_handles, (path)) diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index f58977b5aa9..42b4b8dc013 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -369,15 +369,37 @@ static int cap_chown(vfs_handle_struct *handle, return ret; } -static int cap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +static int cap_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { - char *cappath = capencode(talloc_tos(), path); + struct smb_filename *cap_smb_fname = NULL; + char *cappath = capencode(talloc_tos(), smb_fname->base_name); + int ret; + int saved_errno; if (!cappath) { errno = ENOMEM; return -1; } - return SMB_VFS_NEXT_LCHOWN(handle, cappath, uid, gid); + + cap_smb_fname = synthetic_smb_fname(talloc_tos(), + cappath, + NULL, + NULL); + if (cap_smb_fname == NULL) { + TALLOC_FREE(cappath); + errno = ENOMEM; + return -1; + } + + ret = SMB_VFS_NEXT_LCHOWN(handle, cap_smb_fname, uid, gid); + saved_errno = errno; + TALLOC_FREE(cappath); + TALLOC_FREE(cap_smb_fname); + errno = saved_errno; + return ret; } static int cap_chdir(vfs_handle_struct *handle, const char *path) diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index 814f474c079..4a988b9b3a6 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -559,24 +559,39 @@ static int catia_chown(vfs_handle_struct *handle, } static int catia_lchown(vfs_handle_struct *handle, - const char *path, + const struct smb_filename *smb_fname, uid_t uid, gid_t gid) { char *name = NULL; NTSTATUS status; int ret; + int saved_errno; + struct smb_filename *catia_smb_fname = NULL; - status = catia_string_replace_allocate(handle->conn, path, - &name, vfs_translate_to_unix); + status = catia_string_replace_allocate(handle->conn, + smb_fname->base_name, + &name, + vfs_translate_to_unix); if (!NT_STATUS_IS_OK(status)) { errno = map_errno_from_nt_status(status); return -1; } + catia_smb_fname = synthetic_smb_fname(talloc_tos(), + name, + NULL, + NULL); + if (catia_smb_fname == NULL) { + TALLOC_FREE(name); + errno = ENOMEM; + return -1; + } - ret = SMB_VFS_NEXT_LCHOWN(handle, name, uid, gid); + ret = SMB_VFS_NEXT_LCHOWN(handle, catia_smb_fname, uid, gid); + saved_errno = errno; TALLOC_FREE(name); - + TALLOC_FREE(catia_smb_fname); + errno = saved_errno; return ret; } diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index d185bd0c0b5..b609d72bff9 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -729,12 +729,18 @@ static int cephwrap_fchown(struct vfs_handle_struct *handle, files_struct *fsp, return result; } -static int cephwrap_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +static int cephwrap_lchown(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int result; - - DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", handle, path, uid, gid)); - result = ceph_lchown(handle->data, path, uid, gid); + DEBUG(10, ("[CEPH] lchown(%p, %s, %d, %d)\n", + handle, + smb_fname->base_name, + uid, + gid)); + result = ceph_lchown(handle->data, smb_fname->base_name, uid, gid); DEBUG(10, ("[CEPH] lchown(...) = %d\n", result)); WRAP_RETURN(result); } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 604ee4519b7..4de965e239c 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -1772,12 +1772,15 @@ static int vfswrap_fchown(vfs_handle_struct *handle, files_struct *fsp, uid_t ui #endif } -static int vfswrap_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +static int vfswrap_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int result; START_PROFILE(syscall_lchown); - result = lchown(path, uid, gid); + result = lchown(smb_fname->base_name, uid, gid); END_PROFILE(syscall_lchown); return result; } diff --git a/source3/modules/vfs_fake_acls.c b/source3/modules/vfs_fake_acls.c index cb907d0ca98..491e1ac1ea8 100644 --- a/source3/modules/vfs_fake_acls.c +++ b/source3/modules/vfs_fake_acls.c @@ -427,7 +427,10 @@ static int fake_acls_chown(vfs_handle_struct *handle, return 0; } -static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +static int fake_acls_lchown(vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int ret; uint8_t id_buf[4]; @@ -441,14 +444,24 @@ static int fake_acls_lchown(vfs_handle_struct *handle, const char *path, uid_t u * to. */ SIVAL(id_buf, 0, uid); - ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_UID, id_buf, sizeof(id_buf), 0); + ret = SMB_VFS_NEXT_SETXATTR(handle, + smb_fname->base_name, + FAKE_UID, + id_buf, + sizeof(id_buf), + 0); if (ret != 0) { return ret; } } if (gid != -1) { SIVAL(id_buf, 0, gid); - ret = SMB_VFS_NEXT_SETXATTR(handle, path, FAKE_GID, id_buf, sizeof(id_buf), 0); + ret = SMB_VFS_NEXT_SETXATTR(handle, + smb_fname->base_name, + FAKE_GID, + id_buf, + sizeof(id_buf), + 0); if (ret != 0) { return ret; } diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 309158a41c2..d29064b00d1 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -1450,14 +1450,16 @@ static int smb_full_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, } static int smb_full_audit_lchown(vfs_handle_struct *handle, - const char *path, uid_t uid, gid_t gid) + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int result; - result = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); + result = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); do_log(SMB_VFS_OP_LCHOWN, (result >= 0), handle, "%s|%ld|%ld", - path, (long int)uid, (long int)gid); + smb_fname->base_name, (long int)uid, (long int)gid); return result; } diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index b61bb14ffa4..e2026729190 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -956,9 +956,11 @@ static int vfs_gluster_fchown(struct vfs_handle_struct *handle, } static int vfs_gluster_lchown(struct vfs_handle_struct *handle, - const char *path, uid_t uid, gid_t gid) + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { - return glfs_lchown(handle->data, path, uid, gid); + return glfs_lchown(handle->data, smb_fname->base_name, uid, gid); } static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const char *path) diff --git a/source3/modules/vfs_media_harmony.c b/source3/modules/vfs_media_harmony.c index 73b418ef181..67e2541c123 100644 --- a/source3/modules/vfs_media_harmony.c +++ b/source3/modules/vfs_media_harmony.c @@ -1614,34 +1614,31 @@ out: * Failure: set errno, return -1 */ static int mh_lchown(vfs_handle_struct *handle, - const char *path, + const struct smb_filename *smb_fname, uid_t uid, gid_t gid) { int status; - char *clientPath; - TALLOC_CTX *ctx; + struct smb_filename *clientFname = NULL; DEBUG(MH_INFO_DEBUG, ("Entering mh_lchown\n")); - if (!is_in_media_files(path)) + if (!is_in_media_files(smb_fname->base_name)) { - status = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); + status = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); goto out; } - clientPath = NULL; - ctx = talloc_tos(); - - if ((status = alloc_get_client_path(handle, ctx, - path, - &clientPath))) - { + status = alloc_get_client_smb_fname(handle, + talloc_tos(), + smb_fname, + &clientFname); + if (status != 0) { goto err; } - status = SMB_VFS_NEXT_LCHOWN(handle, clientPath, uid, gid); + status = SMB_VFS_NEXT_LCHOWN(handle, clientFname, uid, gid); err: - TALLOC_FREE(clientPath); + TALLOC_FREE(clientFname); out: return status; } diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c index 13ad402f89b..2b67b913246 100644 --- a/source3/modules/vfs_netatalk.c +++ b/source3/modules/vfs_netatalk.c @@ -433,7 +433,10 @@ exit_chown: return ret; } -static int atalk_lchown(struct vfs_handle_struct *handle, const char *path, uid_t uid, gid_t gid) +static int atalk_lchown(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int ret = 0; char *adbl_path = 0; @@ -442,14 +445,12 @@ static int atalk_lchown(struct vfs_handle_struct *handle, const char *path, uid_ SMB_STRUCT_STAT orig_info; TALLOC_CTX *ctx; - ret = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); - - if (!path) return ret; + ret = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); if (!(ctx = talloc_init("lchown_file"))) return ret; - if (atalk_build_paths(ctx, handle->conn->cwd, path, + if (atalk_build_paths(ctx, handle->conn->cwd, smb_fname->base_name, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) goto exit_lchown; diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 68bc84b58d9..30dae9814df 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1185,19 +1185,23 @@ static int smb_time_audit_fchown(vfs_handle_struct *handle, files_struct *fsp, } static int smb_time_audit_lchown(vfs_handle_struct *handle, - const char *path, uid_t uid, gid_t gid) + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int result; struct timespec ts1,ts2; double timediff; clock_gettime_mono(&ts1); - result = SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); + result = SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); clock_gettime_mono(&ts2); timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; if (timediff > audit_timeout) { - smb_time_audit_log_fname("lchown", timediff, path); + smb_time_audit_log_fname("lchown", + timediff, + smb_fname->base_name); } return result; diff --git a/source3/modules/vfs_unityed_media.c b/source3/modules/vfs_unityed_media.c index 84191cc571f..d46b376099f 100644 --- a/source3/modules/vfs_unityed_media.c +++ b/source3/modules/vfs_unityed_media.c @@ -1236,28 +1236,30 @@ err: } static int um_lchown(vfs_handle_struct *handle, - const char *path, - uid_t uid, - gid_t gid) + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { int status; - char *client_path = NULL; + struct smb_filename *client_fname = NULL; DEBUG(10, ("Entering um_lchown\n")); - if (!is_in_media_files(path)) { - return SMB_VFS_NEXT_LCHOWN(handle, path, uid, gid); + if (!is_in_media_files(smb_fname->base_name)) { + return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); } - status = alloc_get_client_path(handle, talloc_tos(), - path, &client_path); + status = alloc_get_client_smb_fname(handle, + talloc_tos(), + smb_fname, + &client_fname); if (status != 0) { goto err; } - status = SMB_VFS_NEXT_LCHOWN(handle, client_path, uid, gid); + status = SMB_VFS_NEXT_LCHOWN(handle, client_fname, uid, gid); err: - TALLOC_FREE(client_path); + TALLOC_FREE(client_fname); return status; } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index efa7bed1104..2cc14156763 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -592,8 +592,10 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, } become_root(); - ret = SMB_VFS_LCHOWN(conn, ".", smb_fname_parent->st.st_ex_uid, - (gid_t)-1); + ret = SMB_VFS_LCHOWN(conn, + smb_fname_cwd, + smb_fname_parent->st.st_ex_uid, + (gid_t)-1); unbecome_root(); if (ret == -1) { status = map_nt_error_from_unix(errno); diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 2477003e7e2..8cd03c49900 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -7541,7 +7541,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * UNIX extensions calls must always operate * on symlinks. */ - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, + ret = SMB_VFS_LCHOWN(conn, smb_fname, set_owner, (gid_t)-1); } @@ -7573,7 +7573,7 @@ static NTSTATUS smb_set_file_unix_basic(connection_struct *conn, * UNIX extensions calls must always operate * on symlinks. */ - ret = SMB_VFS_LCHOWN(conn, smb_fname->base_name, (uid_t)-1, + ret = SMB_VFS_LCHOWN(conn, smb_fname, (uid_t)-1, set_grp); } if (ret != 0) { diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 8b87b32f4b1..878d8b11c5d 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -1898,21 +1898,23 @@ int smb_vfs_call_fchown(struct vfs_handle_struct *handle, return handle->fns->fchown_fn(handle, fsp, uid, gid); } -int smb_vfs_call_lchown(struct vfs_handle_struct *handle, const char *path, - uid_t uid, gid_t gid) +int smb_vfs_call_lchown(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname, + uid_t uid, + gid_t gid) { VFS_FIND(lchown); - return handle->fns->lchown_fn(handle, path, uid, gid); + return handle->fns->lchown_fn(handle, smb_fname, uid, gid); } NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) { int ret; bool as_root = false; - const char *path; char *saved_dir = NULL; char *parent_dir = NULL; NTSTATUS status; + struct smb_filename *local_smb_fname = NULL; if (fsp->fh->fd != -1) { /* Try fchown. */ @@ -1927,6 +1929,13 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) as_root = (geteuid() == 0); + /* + * FIXME. The logic around as_root and FSP_POSIX_FLAGS_OPEN + * is way too complex and is a security issue waiting to + * happen. This should be simplified into separate if + * blocks. JRA. + */ + if (as_root) { /* * We are being asked to chown as root. Make @@ -1935,7 +1944,6 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) * don't deref any symbolic links. */ const char *final_component = NULL; - struct smb_filename local_fname; saved_dir = vfs_GetWd(talloc_tos(),fsp->conn); if (!saved_dir) { @@ -1959,29 +1967,35 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) return map_nt_error_from_unix(errno); } - ZERO_STRUCT(local_fname); - local_fname.base_name = discard_const_p(char, final_component); + local_smb_fname = synthetic_smb_fname(talloc_tos(), + final_component, + NULL, + NULL); + if (local_smb_fname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto out; + } /* Must use lstat here. */ - ret = SMB_VFS_LSTAT(fsp->conn, &local_fname); + ret = SMB_VFS_LSTAT(fsp->conn, local_smb_fname); if (ret == -1) { status = map_nt_error_from_unix(errno); goto out; } /* Ensure it matches the fsp stat. */ - if (!check_same_stat(&local_fname.st, &fsp->fsp_name->st)) { + if (!check_same_stat(&local_smb_fname->st, + &fsp->fsp_name->st)) { status = NT_STATUS_ACCESS_DENIED; goto out; } - path = final_component; } else { - path = fsp->fsp_name->base_name; - } + local_smb_fname = fsp->fsp_name; + } if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || as_root) { ret = SMB_VFS_LCHOWN(fsp->conn, - path, + local_smb_fname, uid, gid); } else { ret = SMB_VFS_CHOWN(fsp->conn, @@ -1999,6 +2013,7 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) if (as_root) { vfs_ChDir(fsp->conn,saved_dir); + TALLOC_FREE(local_smb_fname); TALLOC_FREE(saved_dir); TALLOC_FREE(parent_dir); }