From 6acb0d6ca08d72f776d3ba9dc934261a481aa737 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 29 Jun 2017 11:29:33 -0700 Subject: [PATCH] s3: VFS: Change SMB_VFS_CHDIR to use const struct smb_filename * instead of const char *. We need to migrate all pathname based VFS calls to use a struct to finish modernising the VFS with extra timestamp and flags parameters. Signed-off-by: Jeremy Allison Reviewed-by: Richard Sharpe --- examples/VFS/skel_opaque.c | 3 +- examples/VFS/skel_transparent.c | 5 +- source3/include/vfs.h | 8 ++- source3/include/vfs_macros.h | 8 +-- source3/modules/vfs_acl_common.c | 20 +++--- source3/modules/vfs_cap.c | 32 +++++++-- source3/modules/vfs_catia.c | 22 ++++-- source3/modules/vfs_ceph.c | 12 ++-- source3/modules/vfs_default.c | 17 +++-- source3/modules/vfs_full_audit.c | 7 +- source3/modules/vfs_glusterfs.c | 5 +- source3/modules/vfs_media_harmony.c | 26 +++---- source3/modules/vfs_shadow_copy2.c | 28 ++++++-- source3/modules/vfs_snapper.c | 42 ++++++++--- source3/modules/vfs_time_audit.c | 9 ++- source3/modules/vfs_unityed_media.c | 18 ++--- source3/printing/nt_printing.c | 21 +++--- source3/rpc_server/srvsvc/srv_srvsvc_nt.c | 31 +++----- source3/smbd/dir.c | 17 +++-- source3/smbd/msdfs.c | 83 ++++++++++++++------- source3/smbd/open.c | 87 ++++++++++++++++------- source3/smbd/proto.h | 9 +-- source3/smbd/service.c | 27 +++++-- source3/smbd/vfs.c | 52 ++++++++++---- source3/torture/cmd_vfs.c | 3 +- 25 files changed, 400 insertions(+), 192 deletions(-) diff --git a/examples/VFS/skel_opaque.c b/examples/VFS/skel_opaque.c index d5c468ebd99..fd81ca03561 100644 --- a/examples/VFS/skel_opaque.c +++ b/examples/VFS/skel_opaque.c @@ -412,7 +412,8 @@ static int skel_lchown(vfs_handle_struct *handle, return -1; } -static int skel_chdir(vfs_handle_struct *handle, const char *path) +static int skel_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { errno = ENOSYS; return -1; diff --git a/examples/VFS/skel_transparent.c b/examples/VFS/skel_transparent.c index 93872769422..4c061ca329e 100644 --- a/examples/VFS/skel_transparent.c +++ b/examples/VFS/skel_transparent.c @@ -515,9 +515,10 @@ static int skel_lchown(vfs_handle_struct *handle, return SMB_VFS_NEXT_LCHOWN(handle, smb_fname, uid, gid); } -static int skel_chdir(vfs_handle_struct *handle, const char *path) +static int skel_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { - return SMB_VFS_NEXT_CHDIR(handle, path); + return SMB_VFS_NEXT_CHDIR(handle, smb_fname); } static char *skel_getwd(vfs_handle_struct *handle) diff --git a/source3/include/vfs.h b/source3/include/vfs.h index db555f2cc2b..f5ac5b5c82e 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -228,6 +228,8 @@ to const struct smb_filename * */ /* Version 37 - Change symlink from const char * to const struct smb_filename * */ +/* Version 37 - Change chdir from const char * + to const struct smb_filename * */ #define SMB_VFS_INTERFACE_VERSION 37 @@ -731,7 +733,8 @@ struct vfs_fn_pointers { const struct smb_filename *smb_fname, uid_t uid, gid_t gid); - int (*chdir_fn)(struct vfs_handle_struct *handle, const char *path); + int (*chdir_fn)(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname); char *(*getwd_fn)(struct vfs_handle_struct *handle); int (*ntimes_fn)(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, @@ -1232,7 +1235,8 @@ 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); +int smb_vfs_call_chdir(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname); char *smb_vfs_call_getwd(struct vfs_handle_struct *handle); int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 77646b45f06..367009bad07 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -266,10 +266,10 @@ #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)) -#define SMB_VFS_NEXT_CHDIR(handle, path) \ - smb_vfs_call_chdir((handle)->next, (path)) +#define SMB_VFS_CHDIR(conn, smb_fname) \ + smb_vfs_call_chdir((conn)->vfs_handles, (smb_fname)) +#define SMB_VFS_NEXT_CHDIR(handle, smb_fname) \ + smb_vfs_call_chdir((handle)->next, (smb_fname)) #define SMB_VFS_GETWD(conn) \ smb_vfs_call_getwd((conn)->vfs_handles) diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c index bd1d755c91f..3b054df2b7d 100644 --- a/source3/modules/vfs_acl_common.c +++ b/source3/modules/vfs_acl_common.c @@ -1288,7 +1288,7 @@ static NTSTATUS fset_nt_acl_common(vfs_handle_struct *handle, files_struct *fsp, } static int acl_common_remove_object(vfs_handle_struct *handle, - const char *path, + const struct smb_filename *smb_fname, bool is_directory) { connection_struct *conn = handle->conn; @@ -1297,17 +1297,20 @@ static int acl_common_remove_object(vfs_handle_struct *handle, int ret = 0; char *parent_dir = NULL; const char *final_component = NULL; - struct smb_filename local_fname; + struct smb_filename local_fname = {0}; + struct smb_filename parent_dir_fname = {0}; int saved_errno = 0; char *saved_dir = NULL; + struct smb_filename saved_dir_fname = {0}; saved_dir = vfs_GetWd(talloc_tos(),conn); if (!saved_dir) { saved_errno = errno; goto out; } + saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; - if (!parent_dirname(talloc_tos(), path, + if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir, &final_component)) { saved_errno = ENOMEM; goto out; @@ -1316,14 +1319,15 @@ static int acl_common_remove_object(vfs_handle_struct *handle, DBG_DEBUG("removing %s %s/%s\n", is_directory ? "directory" : "file", parent_dir, final_component); + parent_dir_fname = (struct smb_filename) { .base_name = parent_dir }; + /* cd into the parent dir to pin it. */ - ret = vfs_ChDir(conn, parent_dir); + ret = vfs_ChDir(conn, &parent_dir_fname); if (ret == -1) { saved_errno = errno; goto out; } - ZERO_STRUCT(local_fname); local_fname.base_name = discard_const_p(char, final_component); /* Must use lstat here. */ @@ -1371,7 +1375,7 @@ static int acl_common_remove_object(vfs_handle_struct *handle, TALLOC_FREE(parent_dir); if (saved_dir) { - vfs_ChDir(conn, saved_dir); + vfs_ChDir(conn, &saved_dir_fname); } if (saved_errno) { errno = saved_errno; @@ -1393,7 +1397,7 @@ static int rmdir_acl_common(struct vfs_handle_struct *handle, /* Failed due to access denied, see if we need to root override. */ return acl_common_remove_object(handle, - smb_fname->base_name, + smb_fname, true); } @@ -1422,7 +1426,7 @@ static int unlink_acl_common(struct vfs_handle_struct *handle, return -1; } return acl_common_remove_object(handle, - smb_fname->base_name, + smb_fname, false); } diff --git a/source3/modules/vfs_cap.c b/source3/modules/vfs_cap.c index c07a05954c0..44a81bbcefb 100644 --- a/source3/modules/vfs_cap.c +++ b/source3/modules/vfs_cap.c @@ -436,16 +436,40 @@ static int cap_lchown(vfs_handle_struct *handle, return ret; } -static int cap_chdir(vfs_handle_struct *handle, const char *path) +static int cap_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { - 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 = 0; if (!cappath) { errno = ENOMEM; return -1; } - DEBUG(3,("cap: cap_chdir for %s\n", path)); - return SMB_VFS_NEXT_CHDIR(handle, cappath); + DEBUG(3,("cap: cap_chdir for %s\n", smb_fname->base_name)); + + cap_smb_fname = synthetic_smb_fname(talloc_tos(), + cappath, + NULL, + NULL, + smb_fname->flags); + if (cap_smb_fname == NULL) { + TALLOC_FREE(cappath); + errno = ENOMEM; + return -1; + } + ret = SMB_VFS_NEXT_CHDIR(handle, cap_smb_fname); + if (ret == -1) { + saved_errno = errno; + } + TALLOC_FREE(cappath); + TALLOC_FREE(cap_smb_fname); + if (saved_errno != 0) { + errno = saved_errno; + } + return ret; } static int cap_ntimes(vfs_handle_struct *handle, diff --git a/source3/modules/vfs_catia.c b/source3/modules/vfs_catia.c index ed16e43aa38..7db50a26206 100644 --- a/source3/modules/vfs_catia.c +++ b/source3/modules/vfs_catia.c @@ -991,21 +991,35 @@ static int catia_mkdir(vfs_handle_struct *handle, } static int catia_chdir(vfs_handle_struct *handle, - const char *path) + const struct smb_filename *smb_fname) { char *name = NULL; + struct smb_filename *catia_smb_fname = NULL; NTSTATUS status; int ret; - 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; } - ret = SMB_VFS_NEXT_CHDIR(handle, name); + catia_smb_fname = synthetic_smb_fname(talloc_tos(), + name, + NULL, + NULL, + smb_fname->flags); + if (catia_smb_fname == NULL) { + TALLOC_FREE(name); + errno = ENOMEM; + return -1; + } + ret = SMB_VFS_NEXT_CHDIR(handle, catia_smb_fname); TALLOC_FREE(name); + TALLOC_FREE(catia_smb_fname); return ret; } diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 7e2bd0e95d2..6b298a2e38f 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -931,18 +931,20 @@ static int cephwrap_lchown(struct vfs_handle_struct *handle, WRAP_RETURN(result); } -static int cephwrap_chdir(struct vfs_handle_struct *handle, const char *path) +static int cephwrap_chdir(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { int result = -1; - DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, path); + DBG_DEBUG("[CEPH] chdir(%p, %s)\n", handle, smb_fname->base_name); /* * If the path is just / use chdir because Ceph is below / and * cannot deal with changing directory above its mount point */ - if (path && !strcmp(path, "/")) - return chdir(path); + if (!strcmp(smb_fname->base_name, "/")) { + return chdir(smb_fname->base_name); + } - result = ceph_chdir(handle->data, path); + result = ceph_chdir(handle->data, smb_fname->base_name); DBG_DEBUG("[CEPH] chdir(...) = %d\n", result); WRAP_RETURN(result); } diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index d339f39aa06..7a2fae2156d 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -228,10 +228,18 @@ static NTSTATUS vfswrap_get_dfs_referrals(struct vfs_handle_struct *handle, !handle->conn->sconn->using_smb2, junction, &consumedcnt, &self_referral); if (!NT_STATUS_IS_OK(status)) { - vfs_ChDir(handle->conn, handle->conn->connectpath); + struct smb_filename connectpath_fname = { + .base_name = handle->conn->connectpath + }; + vfs_ChDir(handle->conn, &connectpath_fname); return status; } - vfs_ChDir(handle->conn, handle->conn->connectpath); + { + struct smb_filename connectpath_fname = { + .base_name = handle->conn->connectpath + }; + vfs_ChDir(handle->conn, &connectpath_fname); + } if (!self_referral) { pathnamep[consumedcnt] = '\0'; @@ -2080,12 +2088,13 @@ static int vfswrap_lchown(vfs_handle_struct *handle, return result; } -static int vfswrap_chdir(vfs_handle_struct *handle, const char *path) +static int vfswrap_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { int result; START_PROFILE(syscall_chdir); - result = chdir(path); + result = chdir(smb_fname->base_name); END_PROFILE(syscall_chdir); return result; } diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 1267ef3d226..5d35c340371 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -1509,13 +1509,14 @@ static int smb_full_audit_lchown(vfs_handle_struct *handle, } static int smb_full_audit_chdir(vfs_handle_struct *handle, - const char *path) + const struct smb_filename *smb_fname) { int result; - result = SMB_VFS_NEXT_CHDIR(handle, path); + result = SMB_VFS_NEXT_CHDIR(handle, smb_fname); - do_log(SMB_VFS_OP_CHDIR, (result >= 0), handle, "chdir|%s", path); + do_log(SMB_VFS_OP_CHDIR, (result >= 0), handle, "chdir|%s", + smb_fname->base_name); return result; } diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 2528959d968..833f093ac42 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -1070,9 +1070,10 @@ static int vfs_gluster_lchown(struct vfs_handle_struct *handle, return glfs_lchown(handle->data, smb_fname->base_name, uid, gid); } -static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const char *path) +static int vfs_gluster_chdir(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { - return glfs_chdir(handle->data, path); + return glfs_chdir(handle->data, smb_fname->base_name); } static char *vfs_gluster_getwd(struct vfs_handle_struct *handle) diff --git a/source3/modules/vfs_media_harmony.c b/source3/modules/vfs_media_harmony.c index ca8d6ce1a6d..bd774b83909 100644 --- a/source3/modules/vfs_media_harmony.c +++ b/source3/modules/vfs_media_harmony.c @@ -1648,32 +1648,28 @@ out: * Failure: set errno, return -1 */ static int mh_chdir(vfs_handle_struct *handle, - const char *path) + const struct smb_filename *smb_fname) { int status; - char *clientPath; - TALLOC_CTX *ctx; + struct smb_filename *clientFname = NULL; DEBUG(MH_INFO_DEBUG, ("Entering mh_chdir\n")); - if (!is_in_media_files(path)) - { - status = SMB_VFS_NEXT_CHDIR(handle, path); + if (!is_in_media_files(smb_fname->base_name)) { + status = SMB_VFS_NEXT_CHDIR(handle, smb_fname); 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_CHDIR(handle, clientPath); + status = SMB_VFS_NEXT_CHDIR(handle, clientFname); err: - TALLOC_FREE(clientPath); + TALLOC_FREE(clientFname); out: return status; } diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 31ef499527e..4b5a7bccc97 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1550,7 +1550,7 @@ static void store_cwd_data(vfs_handle_struct *handle, } static int shadow_copy2_chdir(vfs_handle_struct *handle, - const char *fname) + const struct smb_filename *smb_fname) { time_t timestamp = 0; char *stripped = NULL; @@ -1559,9 +1559,14 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, int saved_errno = 0; char *conv = NULL; size_t rootpath_len = 0; + struct smb_filename *conv_smb_fname = NULL; - if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), handle, fname, - ×tamp, &stripped, &snappath)) { + if (!shadow_copy2_strip_snapshot_internal(talloc_tos(), + handle, + smb_fname->base_name, + ×tamp, + &stripped, + &snappath)) { return -1; } if (stripped != NULL) { @@ -1574,10 +1579,22 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, if (conv == NULL) { return -1; } - fname = conv; + conv_smb_fname = synthetic_smb_fname(talloc_tos(), + conv, + NULL, + NULL, + smb_fname->flags); + } else { + conv_smb_fname = cp_smb_filename(talloc_tos(), smb_fname); } - ret = SMB_VFS_NEXT_CHDIR(handle, fname); + if (conv_smb_fname == NULL) { + TALLOC_FREE(conv); + errno = ENOMEM; + return -1; + } + + ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname); if (ret == -1) { saved_errno = errno; } @@ -1594,6 +1611,7 @@ static int shadow_copy2_chdir(vfs_handle_struct *handle, TALLOC_FREE(stripped); TALLOC_FREE(conv); + TALLOC_FREE(conv_smb_fname); if (saved_errno != 0) { errno = saved_errno; diff --git a/source3/modules/vfs_snapper.c b/source3/modules/vfs_snapper.c index 4c814327feb..05d57671db7 100644 --- a/source3/modules/vfs_snapper.c +++ b/source3/modules/vfs_snapper.c @@ -2344,29 +2344,49 @@ static int snapper_gmt_chown(vfs_handle_struct *handle, } static int snapper_gmt_chdir(vfs_handle_struct *handle, - const char *fname) + const struct smb_filename *smb_fname) { - time_t timestamp; - char *stripped; - int ret, saved_errno; - char *conv; + time_t timestamp = 0; + char *stripped = NULL; + int ret; + int saved_errno = 0; + char *conv = NULL; + struct smb_filename *conv_smb_fname = NULL; - if (!snapper_gmt_strip_snapshot(talloc_tos(), handle, fname, - ×tamp, &stripped)) { + if (!snapper_gmt_strip_snapshot(talloc_tos(), + handle, + smb_fname->base_name, + ×tamp, + &stripped)) { return -1; } if (timestamp == 0) { - return SMB_VFS_NEXT_CHDIR(handle, fname); + return SMB_VFS_NEXT_CHDIR(handle, smb_fname); } conv = snapper_gmt_convert(talloc_tos(), handle, stripped, timestamp); TALLOC_FREE(stripped); if (conv == NULL) { return -1; } - ret = SMB_VFS_NEXT_CHDIR(handle, conv); - saved_errno = errno; + conv_smb_fname = synthetic_smb_fname(talloc_tos(), + conv, + NULL, + NULL, + smb_fname->flags); + if (conv_smb_fname == NULL) { + TALLOC_FREE(conv); + errno = ENOMEM; + return -1; + } + ret = SMB_VFS_NEXT_CHDIR(handle, conv_smb_fname); + if (ret == -1) { + saved_errno = errno; + } TALLOC_FREE(conv); - errno = saved_errno; + TALLOC_FREE(conv_smb_fname); + if (saved_errno != 0) { + errno = saved_errno; + } return ret; } diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index d3992018542..820de3ffa2c 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1236,19 +1236,22 @@ static int smb_time_audit_lchown(vfs_handle_struct *handle, return result; } -static int smb_time_audit_chdir(vfs_handle_struct *handle, const char *path) +static int smb_time_audit_chdir(vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { int result; struct timespec ts1,ts2; double timediff; clock_gettime_mono(&ts1); - result = SMB_VFS_NEXT_CHDIR(handle, path); + result = SMB_VFS_NEXT_CHDIR(handle, smb_fname); clock_gettime_mono(&ts2); timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; if (timediff > audit_timeout) { - smb_time_audit_log_fname("chdir", timediff, path); + smb_time_audit_log_fname("chdir", + timediff, + smb_fname->base_name); } return result; diff --git a/source3/modules/vfs_unityed_media.c b/source3/modules/vfs_unityed_media.c index 45232e1781c..435deeb0579 100644 --- a/source3/modules/vfs_unityed_media.c +++ b/source3/modules/vfs_unityed_media.c @@ -1267,27 +1267,29 @@ err: } static int um_chdir(vfs_handle_struct *handle, - const char *path) + const struct smb_filename *smb_fname) { int status; - char *client_path = NULL; + struct smb_filename *client_fname = NULL; DEBUG(10, ("Entering um_chdir\n")); - if (!is_in_media_files(path)) { - return SMB_VFS_NEXT_CHDIR(handle, path); + if (!is_in_media_files(smb_fname->base_name)) { + return SMB_VFS_NEXT_CHDIR(handle, smb_fname); } - 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_CHDIR(handle, client_path); + status = SMB_VFS_NEXT_CHDIR(handle, client_fname); err: - TALLOC_FREE(client_path); + TALLOC_FREE(client_fname); return status; } diff --git a/source3/printing/nt_printing.c b/source3/printing/nt_printing.c index f87703905ed..47590f67fc7 100644 --- a/source3/printing/nt_printing.c +++ b/source3/printing/nt_printing.c @@ -674,7 +674,7 @@ static uint32_t get_correct_cversion(struct auth_session_info *session_info, struct smb_filename *smb_fname = NULL; files_struct *fsp = NULL; connection_struct *conn = NULL; - char *oldcwd; + struct smb_filename *oldcwd_fname = NULL; char *printdollar = NULL; char *printdollar_path = NULL; char *working_dir = NULL; @@ -733,7 +733,7 @@ static uint32_t get_correct_cversion(struct auth_session_info *session_info, &conn, printdollar_snum, working_dir, - session_info, &oldcwd); + session_info, &oldcwd_fname); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("get_correct_cversion: create_conn_struct " "returned %s\n", nt_errstr(nt_status))); @@ -851,7 +851,8 @@ static uint32_t get_correct_cversion(struct auth_session_info *session_info, close_file(NULL, fsp, NORMAL_CLOSE); } if (conn != NULL) { - vfs_ChDir(conn, oldcwd); + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); } @@ -1168,7 +1169,7 @@ WERROR move_driver_to_download_area(struct auth_session_info *session_info, int i; TALLOC_CTX *ctx = talloc_tos(); int ver = 0; - char *oldcwd; + struct smb_filename *oldcwd_fname = NULL; char *printdollar = NULL; int printdollar_snum; WERROR err = WERR_OK; @@ -1209,7 +1210,7 @@ WERROR move_driver_to_download_area(struct auth_session_info *session_info, &conn, printdollar_snum, lp_path(talloc_tos(), printdollar_snum), - session_info, &oldcwd); + session_info, &oldcwd_fname); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("move_driver_to_download_area: create_conn_struct " "returned %s\n", nt_errstr(nt_status))); @@ -1374,7 +1375,8 @@ WERROR move_driver_to_download_area(struct auth_session_info *session_info, TALLOC_FREE(smb_dname); if (conn != NULL) { - vfs_ChDir(conn, oldcwd); + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); } @@ -1728,7 +1730,7 @@ bool delete_driver_files(const struct auth_session_info *session_info, const char *short_arch; connection_struct *conn; NTSTATUS nt_status; - char *oldcwd; + struct smb_filename *oldcwd_fname = NULL; char *printdollar = NULL; int printdollar_snum; bool ret = false; @@ -1754,7 +1756,7 @@ bool delete_driver_files(const struct auth_session_info *session_info, &conn, printdollar_snum, lp_path(talloc_tos(), printdollar_snum), - session_info, &oldcwd); + session_info, &oldcwd_fname); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("delete_driver_files: create_conn_struct " "returned %s\n", nt_errstr(nt_status))); @@ -1823,7 +1825,8 @@ bool delete_driver_files(const struct auth_session_info *session_info, unbecome_user(); err_free_conn: if (conn != NULL) { - vfs_ChDir(conn, oldcwd); + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); } diff --git a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c index fdf42ea030b..f3173aee42f 100644 --- a/source3/rpc_server/srvsvc/srv_srvsvc_nt.c +++ b/source3/rpc_server/srvsvc/srv_srvsvc_nt.c @@ -2323,7 +2323,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, struct sec_desc_buf *sd_buf = NULL; files_struct *fsp = NULL; int snum; - char *oldcwd = NULL; + struct smb_filename *oldcwd_fname = NULL; uint32_t ucf_flags = 0; ZERO_STRUCT(st); @@ -2348,7 +2348,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, server_messaging_context(), &conn, snum, lp_path(talloc_tos(), snum), - p->session_info, &oldcwd); + p->session_info, &oldcwd_fname); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("create_conn_struct failed: %s\n", nt_errstr(nt_status))); @@ -2423,12 +2423,7 @@ WERROR _srvsvc_NetGetFileSecurity(struct pipes_struct *p, *r->out.sd_buf = sd_buf; - close_file(NULL, fsp, NORMAL_CLOSE); - vfs_ChDir(conn, oldcwd); - SMB_VFS_DISCONNECT(conn); - conn_free(conn); werr = WERR_OK; - goto done; error_exit: @@ -2436,8 +2431,9 @@ error_exit: close_file(NULL, fsp, NORMAL_CLOSE); } - if (oldcwd) { - vfs_ChDir(conn, oldcwd); + if (oldcwd_fname) { + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); } if (conn) { @@ -2445,8 +2441,6 @@ error_exit: conn_free(conn); } - done: - TALLOC_FREE(smb_fname); return werr; @@ -2468,7 +2462,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, WERROR werr; connection_struct *conn = NULL; int snum; - char *oldcwd = NULL; + struct smb_filename *oldcwd_fname = NULL; struct security_descriptor *psd = NULL; uint32_t security_info_sent = 0; uint32_t ucf_flags = 0; @@ -2497,7 +2491,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, server_messaging_context(), &conn, snum, lp_path(talloc_tos(), snum), - p->session_info, &oldcwd); + p->session_info, &oldcwd_fname); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(10, ("create_conn_struct failed: %s\n", nt_errstr(nt_status))); @@ -2555,12 +2549,7 @@ WERROR _srvsvc_NetSetFileSecurity(struct pipes_struct *p, goto error_exit; } - close_file(NULL, fsp, NORMAL_CLOSE); - vfs_ChDir(conn, oldcwd); - SMB_VFS_DISCONNECT(conn); - conn_free(conn); werr = WERR_OK; - goto done; error_exit: @@ -2568,8 +2557,9 @@ error_exit: close_file(NULL, fsp, NORMAL_CLOSE); } - if (oldcwd) { - vfs_ChDir(conn, oldcwd); + if (oldcwd_fname) { + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); } if (conn) { @@ -2577,7 +2567,6 @@ error_exit: conn_free(conn); } - done: TALLOC_FREE(smb_fname); return werr; diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 1348d12298c..9391e3c827c 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -399,7 +399,8 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, uint32_t attr) { struct smb_Dir *dir_hnd = NULL; - struct smb_filename *smb_fname_cwd; + struct smb_filename *smb_fname_cwd = NULL; + struct smb_filename saved_dir_fname = {0}; char *saved_dir = vfs_GetWd(talloc_tos(), conn); struct privilege_paths *priv_paths = req->priv_paths; int ret; @@ -408,7 +409,9 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, return NULL; } - if (vfs_ChDir(conn, smb_dname->base_name) == -1) { + saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; + + if (vfs_ChDir(conn, smb_dname) == -1) { return NULL; } @@ -438,7 +441,8 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, out: - vfs_ChDir(conn, saved_dir); + vfs_ChDir(conn, &saved_dir_fname); + TALLOC_FREE(saved_dir); return dir_hnd; } @@ -1679,6 +1683,7 @@ static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx, { struct smb_Dir *dir_hnd = NULL; struct smb_filename *smb_fname_cwd = NULL; + struct smb_filename saved_dir_fname = {0}; char *saved_dir = vfs_GetWd(ctx, conn); NTSTATUS status; @@ -1686,7 +1691,9 @@ static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx, return NULL; } - if (vfs_ChDir(conn, smb_dname->base_name) == -1) { + saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; + + if (vfs_ChDir(conn, smb_dname) == -1) { goto out; } @@ -1731,7 +1738,7 @@ static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx, out: - vfs_ChDir(conn, saved_dir); + vfs_ChDir(conn, &saved_dir_fname); TALLOC_FREE(saved_dir); return dir_hnd; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index 9c25d8ba8fe..d87b9b9bace 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -400,10 +400,12 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, int snum, const char *path, const struct auth_session_info *session_info, - char **poldcwd) + struct smb_filename **poldcwd_fname) { connection_struct *conn; - char *oldcwd; + char *oldcwd = NULL; + struct smb_filename *smb_fname_oldcwd = NULL; + struct smb_filename smb_fname_connectpath = {0}; NTSTATUS status = create_conn_struct(ctx, ev, msg, &conn, @@ -427,17 +429,33 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, return status; } - if (vfs_ChDir(conn,conn->connectpath) != 0) { + smb_fname_oldcwd = synthetic_smb_fname(ctx, + oldcwd, + NULL, + NULL, + 0); + if (smb_fname_oldcwd == NULL) { + status = NT_STATUS_NO_MEMORY; + 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(smb_fname_oldcwd); conn_free(conn); return status; } *pconn = conn; - *poldcwd = oldcwd; + *poldcwd_fname = smb_fname_oldcwd; return NT_STATUS_OK; } @@ -957,7 +975,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, NTSTATUS status = NT_STATUS_NOT_FOUND; bool dummy; struct dfs_path *pdp = talloc(ctx, struct dfs_path); - char *oldpath; + struct smb_filename *oldcwd_fname = NULL; if (!pdp) { return NT_STATUS_NO_MEMORY; @@ -1054,8 +1072,11 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, status = create_conn_struct_cwd(ctx, server_event_context(), server_messaging_context(), - &conn, snum, - lp_path(talloc_tos(), snum), NULL, &oldpath); + &conn, + snum, + lp_path(talloc_tos(), snum), + NULL, + &oldcwd_fname); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(pdp); return status; @@ -1121,7 +1142,8 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, status = NT_STATUS_OK; err_exit: - vfs_ChDir(conn, oldpath); + vfs_ChDir(conn, oldcwd_fname); + TALLOC_FREE(oldcwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); TALLOC_FREE(pdp); @@ -1257,7 +1279,7 @@ bool create_junction(TALLOC_CTX *ctx, static bool junction_to_local_path(const struct junction_map *jucn, char **pp_path_out, connection_struct **conn_out, - char **oldpath) + struct smb_filename **oldpath_fname) { int snum; NTSTATUS status; @@ -1270,7 +1292,10 @@ static bool junction_to_local_path(const struct junction_map *jucn, server_event_context(), server_messaging_context(), conn_out, - snum, lp_path(talloc_tos(), snum), NULL, oldpath); + snum, + lp_path(talloc_tos(), snum), + NULL, + oldpath_fname); if (!NT_STATUS_IS_OK(status)) { return False; } @@ -1280,7 +1305,7 @@ static bool junction_to_local_path(const struct junction_map *jucn, lp_path(talloc_tos(), snum), jucn->volume_name); if (!*pp_path_out) { - vfs_ChDir(*conn_out, *oldpath); + vfs_ChDir(*conn_out, *oldpath_fname); SMB_VFS_DISCONNECT(*conn_out); conn_free(*conn_out); return False; @@ -1291,7 +1316,7 @@ static bool junction_to_local_path(const struct junction_map *jucn, bool create_msdfs_link(const struct junction_map *jucn) { char *path = NULL; - char *cwd; + struct smb_filename *cwd_fname = NULL; char *msdfs_link = NULL; connection_struct *conn; int i=0; @@ -1299,7 +1324,7 @@ bool create_msdfs_link(const struct junction_map *jucn) bool ret = False; struct smb_filename *smb_fname = NULL; - if(!junction_to_local_path(jucn, &path, &conn, &cwd)) { + if(!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) { return False; } @@ -1369,7 +1394,8 @@ bool create_msdfs_link(const struct junction_map *jucn) out: TALLOC_FREE(smb_fname); - vfs_ChDir(conn, cwd); + vfs_ChDir(conn, cwd_fname); + TALLOC_FREE(cwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); return ret; @@ -1378,12 +1404,12 @@ out: bool remove_msdfs_link(const struct junction_map *jucn) { char *path = NULL; - char *cwd; + struct smb_filename *cwd_fname = NULL; connection_struct *conn; bool ret = False; struct smb_filename *smb_fname; - if (!junction_to_local_path(jucn, &path, &conn, &cwd)) { + if (!junction_to_local_path(jucn, &path, &conn, &cwd_fname)) { return false; } @@ -1402,7 +1428,8 @@ bool remove_msdfs_link(const struct junction_map *jucn) } TALLOC_FREE(smb_fname); - vfs_ChDir(conn, cwd); + vfs_ChDir(conn, cwd_fname); + TALLOC_FREE(cwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); return ret; @@ -1422,7 +1449,7 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum); connection_struct *conn; NTSTATUS status; - char *cwd; + struct smb_filename *cwd_fname = NULL; struct smb_filename *smb_fname = NULL; if(*connect_path == '\0') { @@ -1437,7 +1464,10 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) server_event_context(), server_messaging_context(), &conn, - snum, connect_path, NULL, &cwd); + snum, + connect_path, + NULL, + &cwd_fname); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("create_conn_struct failed: %s\n", nt_errstr(status))); @@ -1489,7 +1519,8 @@ static int count_dfs_links(TALLOC_CTX *ctx, int snum) out: TALLOC_FREE(smb_fname); - vfs_ChDir(conn, cwd); + vfs_ChDir(conn, cwd_fname); + TALLOC_FREE(cwd_fname); SMB_VFS_DISCONNECT(conn); conn_free(conn); return cnt; @@ -1512,7 +1543,7 @@ static int form_junctions(TALLOC_CTX *ctx, const char *msdfs_proxy = lp_msdfs_proxy(talloc_tos(), snum); connection_struct *conn; struct referral *ref = NULL; - char *cwd; + struct smb_filename *cwd_fname = NULL; struct smb_filename *smb_fname = NULL; NTSTATUS status; @@ -1531,8 +1562,11 @@ static int form_junctions(TALLOC_CTX *ctx, status = create_conn_struct_cwd(ctx, server_event_context(), server_messaging_context(), - &conn, snum, connect_path, NULL, - &cwd); + &conn, + snum, + connect_path, + NULL, + &cwd_fname); if (!NT_STATUS_IS_OK(status)) { DEBUG(3, ("create_conn_struct failed: %s\n", nt_errstr(status))); @@ -1646,7 +1680,8 @@ out: } TALLOC_FREE(smb_fname); - vfs_ChDir(conn, cwd); + vfs_ChDir(conn, cwd_fname); + TALLOC_FREE(cwd_fname); conn_free(conn); return cnt; } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index fa74f48b66d..031ba11f1d2 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -389,7 +389,7 @@ static int link_errno_convert(int err) } static int non_widelink_open(struct connection_struct *conn, - const char *conn_rootdir, + const struct smb_filename *conn_rootdir_fname, files_struct *fsp, struct smb_filename *smb_fname, int flags, @@ -401,7 +401,7 @@ static int non_widelink_open(struct connection_struct *conn, ****************************************************************************/ static int process_symlink_open(struct connection_struct *conn, - const char *conn_rootdir, + const struct smb_filename *conn_rootdir_fname, files_struct *fsp, struct smb_filename *smb_fname, int flags, @@ -412,6 +412,7 @@ static int process_symlink_open(struct connection_struct *conn, char *link_target = NULL; int link_len = -1; char *oldwd = NULL; + struct smb_filename oldwd_fname = {0}; size_t rootdir_len = 0; char *resolved_name = NULL; bool matched = false; @@ -456,9 +457,11 @@ static int process_symlink_open(struct connection_struct *conn, * does not end in '/'. FIXME ! Should we * smb_assert this ? */ - rootdir_len = strlen(conn_rootdir); + rootdir_len = strlen(conn_rootdir_fname->base_name); - matched = (strncmp(conn_rootdir, resolved_name, rootdir_len) == 0); + matched = (strncmp(conn_rootdir_fname->base_name, + resolved_name, + rootdir_len) == 0); if (!matched) { errno = EACCES; goto out; @@ -486,14 +489,16 @@ static int process_symlink_open(struct connection_struct *conn, goto out; } + oldwd_fname = (struct smb_filename) { .base_name = oldwd }; + /* Ensure we operate from the root of the share. */ - if (vfs_ChDir(conn, conn_rootdir) == -1) { + if (vfs_ChDir(conn, conn_rootdir_fname) == -1) { goto out; } /* And do it all again.. */ fd = non_widelink_open(conn, - conn_rootdir, + conn_rootdir_fname, fsp, smb_fname, flags, @@ -508,7 +513,7 @@ static int process_symlink_open(struct connection_struct *conn, SAFE_FREE(resolved_name); TALLOC_FREE(link_target); if (oldwd != NULL) { - int ret = vfs_ChDir(conn, oldwd); + int ret = vfs_ChDir(conn, &oldwd_fname); if (ret == -1) { smb_panic("unable to get back to old directory\n"); } @@ -525,7 +530,7 @@ static int process_symlink_open(struct connection_struct *conn, ****************************************************************************/ static int non_widelink_open(struct connection_struct *conn, - const char *conn_rootdir, + const struct smb_filename *conn_rootdir_fname, files_struct *fsp, struct smb_filename *smb_fname, int flags, @@ -537,7 +542,9 @@ static int non_widelink_open(struct connection_struct *conn, struct smb_filename *smb_fname_rel = NULL; int saved_errno = 0; char *oldwd = NULL; + struct smb_filename oldwd_fname = {0}; char *parent_dir = NULL; + struct smb_filename parent_dir_fname = {0}; const char *final_component = NULL; if (!parent_dirname(talloc_tos(), @@ -547,13 +554,17 @@ static int non_widelink_open(struct connection_struct *conn, goto out; } + parent_dir_fname = (struct smb_filename) { .base_name = parent_dir }; + oldwd = vfs_GetWd(talloc_tos(), conn); if (oldwd == NULL) { goto out; } + oldwd_fname = (struct smb_filename) { .base_name = oldwd }; + /* Pin parent directory in place. */ - if (vfs_ChDir(conn, parent_dir) == -1) { + if (vfs_ChDir(conn, &parent_dir_fname) == -1) { goto out; } @@ -606,7 +617,7 @@ static int non_widelink_open(struct connection_struct *conn, * to ensure it's under the share definition. */ fd = process_symlink_open(conn, - conn_rootdir, + conn_rootdir_fname, fsp, smb_fname_rel, flags, @@ -634,7 +645,7 @@ static int non_widelink_open(struct connection_struct *conn, TALLOC_FREE(smb_fname_rel); if (oldwd != NULL) { - int ret = vfs_ChDir(conn, oldwd); + int ret = vfs_ChDir(conn, &oldwd_fname); if (ret == -1) { smb_panic("unable to get back to old directory\n"); } @@ -669,22 +680,41 @@ NTSTATUS fd_open(struct connection_struct *conn, /* Ensure path is below share definition. */ if (!lp_widelinks(SNUM(conn))) { + struct smb_filename *conn_rootdir_fname = NULL; const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn, smb_fname->base_name); + int saved_errno = 0; + if (conn_rootdir == NULL) { return NT_STATUS_NO_MEMORY; } + conn_rootdir_fname = synthetic_smb_fname(talloc_tos(), + conn_rootdir, + NULL, + NULL, + 0); + if (conn_rootdir_fname == NULL) { + return NT_STATUS_NO_MEMORY; + } + /* * Only follow symlinks within a share * definition. */ fsp->fh->fd = non_widelink_open(conn, - conn_rootdir, + conn_rootdir_fname, fsp, smb_fname, flags, mode, 0); + if (fsp->fh->fd == -1) { + saved_errno = errno; + } + TALLOC_FREE(conn_rootdir_fname); + if (saved_errno != 0) { + errno = saved_errno; + } } else { fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode); } @@ -800,14 +830,15 @@ void change_file_owner_to_parent(connection_struct *conn, TALLOC_FREE(smb_fname_parent); } -NTSTATUS change_dir_owner_to_parent(connection_struct *conn, - const char *inherit_from_dir, - const char *fname, - SMB_STRUCT_STAT *psbuf) +static NTSTATUS change_dir_owner_to_parent(connection_struct *conn, + const char *inherit_from_dir, + struct smb_filename *smb_dname, + SMB_STRUCT_STAT *psbuf) { struct smb_filename *smb_fname_parent; struct smb_filename *smb_fname_cwd = NULL; char *saved_dir = NULL; + struct smb_filename smb_fname_saved_dir = {0}; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; int ret; @@ -847,12 +878,14 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, goto out; } + smb_fname_saved_dir = (struct smb_filename) { .base_name = saved_dir }; + /* Chdir into the new path. */ - if (vfs_ChDir(conn, fname) == -1) { + if (vfs_ChDir(conn, smb_dname) == -1) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to change " "current working directory to %s. Error " - "was %s\n", fname, strerror(errno) )); + "was %s\n", smb_dname->base_name, strerror(errno) )); goto chdir; } @@ -867,7 +900,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to stat " "directory '.' (%s) Error was %s\n", - fname, strerror(errno))); + smb_dname->base_name, strerror(errno))); goto chdir; } @@ -876,7 +909,8 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, smb_fname_cwd->st.st_ex_ino != psbuf->st_ex_ino) { DEBUG(0,("change_dir_owner_to_parent: " "device/inode on directory %s changed. " - "Refusing to chown !\n", fname )); + "Refusing to chown !\n", + smb_dname->base_name )); status = NT_STATUS_ACCESS_DENIED; goto chdir; } @@ -885,7 +919,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, /* Already this uid - no need to change. */ DEBUG(10,("change_dir_owner_to_parent: directory %s " "is already owned by uid %d\n", - fname, + smb_dname->base_name, (int)smb_fname_cwd->st.st_ex_uid )); status = NT_STATUS_OK; goto chdir; @@ -901,20 +935,23 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn, status = map_nt_error_from_unix(errno); DEBUG(10,("change_dir_owner_to_parent: failed to chown " "directory %s to parent directory uid %u. " - "Error was %s\n", fname, + "Error was %s\n", + smb_dname->base_name, (unsigned int)smb_fname_parent->st.st_ex_uid, strerror(errno) )); } else { DEBUG(10,("change_dir_owner_to_parent: changed ownership of new " "directory %s to parent directory uid %u.\n", - fname, (unsigned int)smb_fname_parent->st.st_ex_uid )); + smb_dname->base_name, + (unsigned int)smb_fname_parent->st.st_ex_uid )); /* Ensure the uid entry is updated. */ psbuf->st_ex_uid = smb_fname_parent->st.st_ex_uid; } chdir: - vfs_ChDir(conn,saved_dir); + vfs_ChDir(conn, &smb_fname_saved_dir); out: + TALLOC_FREE(saved_dir); TALLOC_FREE(smb_fname_parent); TALLOC_FREE(smb_fname_cwd); return status; @@ -3875,7 +3912,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn, /* Change the owner if required. */ if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) { change_dir_owner_to_parent(conn, parent_dir, - smb_dname->base_name, + smb_dname, &smb_dname->st); need_re_stat = true; } diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 722edf3e67c..4823e1170fc 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -510,7 +510,7 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, int snum, const char *path, const struct auth_session_info *session_info, - char **poldcwd); + struct smb_filename **poldcwd_fname); /* The following definitions come from smbd/negprot.c */ @@ -649,10 +649,6 @@ NTSTATUS fd_close(files_struct *fsp); void change_file_owner_to_parent(connection_struct *conn, const char *inherit_from_dir, files_struct *fsp); -NTSTATUS change_dir_owner_to_parent(connection_struct *conn, - const char *inherit_from_dir, - const char *fname, - SMB_STRUCT_STAT *psbuf); bool is_stat_open(uint32_t access_mask); NTSTATUS send_break_message(struct messaging_context *msg_ctx, const struct share_mode_entry *exclusive, @@ -1234,7 +1230,8 @@ int vfs_fill_sparse(files_struct *fsp, off_t len); off_t vfs_transfer_file(files_struct *in, files_struct *out, off_t n); const char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf, char **talloced); -int vfs_ChDir(connection_struct *conn, const char *path); +int vfs_ChDir(connection_struct *conn, + const struct smb_filename *smb_fname); char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn); NTSTATUS check_reduced_name(connection_struct *conn, const char *cwd_name, diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 0376a330e23..47cd0fa19d5 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -95,12 +95,22 @@ bool set_current_service(connection_struct *conn, uint16_t flags, bool do_chdir) snum = SNUM(conn); - if (do_chdir && - vfs_ChDir(conn,conn->connectpath) != 0 && - vfs_ChDir(conn,conn->origpath) != 0) { - DEBUG(((errno!=EACCES)?0:3),("chdir (%s) failed, reason: %s\n", - conn->connectpath, strerror(errno))); - return(False); + { + struct smb_filename connectpath_fname = { + .base_name = conn->connectpath + }; + struct smb_filename origpath_fname = { + .base_name = conn->origpath + }; + + if (do_chdir && + vfs_ChDir(conn, &connectpath_fname) != 0 && + vfs_ChDir(conn, &origpath_fname) != 0) { + DEBUG(((errno!=EACCES)?0:3), + ("chdir (%s) failed, reason: %s\n", + conn->connectpath, strerror(errno))); + return(False); + } } if ((conn == last_conn) && (last_flags == flags)) { @@ -1083,6 +1093,9 @@ connection_struct *make_connection(struct smb_request *req, void close_cnum(connection_struct *conn, uint64_t vuid) { + char rootpath[2] = { '/', '\0'}; + struct smb_filename root_fname = { .base_name = rootpath }; + file_close_conn(conn); if (!IS_IPC(conn)) { @@ -1098,7 +1111,7 @@ void close_cnum(connection_struct *conn, uint64_t vuid) lp_servicename(talloc_tos(), SNUM(conn)))); /* make sure we leave the directory available for unmount */ - vfs_ChDir(conn, "/"); + vfs_ChDir(conn, &root_fname); /* Call VFS disconnect hook */ SMB_VFS_DISCONNECT(conn); diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 5acfb9af38a..40c41ed27fc 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -855,7 +855,7 @@ const char *vfs_readdirname(connection_struct *conn, void *p, A wrapper for vfs_chdir(). ********************************************************************/ -int vfs_ChDir(connection_struct *conn, const char *path) +int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname) { int ret; @@ -863,21 +863,22 @@ int vfs_ChDir(connection_struct *conn, const char *path) LastDir = SMB_STRDUP(""); } - if (ISDOT(path)) { + if (ISDOT(smb_fname->base_name)) { return 0; } - if (*path == '/' && strcsequal(LastDir,path)) { + if (*smb_fname->base_name == '/' && + strcsequal(LastDir,smb_fname->base_name)) { return 0; } - DEBUG(4,("vfs_ChDir to %s\n",path)); + DEBUG(4,("vfs_ChDir to %s\n", smb_fname->base_name)); - ret = SMB_VFS_CHDIR(conn,path); + ret = SMB_VFS_CHDIR(conn, smb_fname); if (ret == 0) { /* Global cache. */ SAFE_FREE(LastDir); - LastDir = SMB_STRDUP(path); + LastDir = SMB_STRDUP(smb_fname->base_name); /* conn cache. */ TALLOC_FREE(conn->cwd); @@ -1009,6 +1010,7 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, const char *last_component = NULL; char *resolved_name = NULL; char *saved_dir = NULL; + struct smb_filename *saved_dir_fname = NULL; struct smb_filename *smb_fname_cwd = NULL; struct privilege_paths *priv_paths = NULL; int ret; @@ -1049,8 +1051,18 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, goto err; } + saved_dir_fname = synthetic_smb_fname(ctx, + saved_dir, + NULL, + NULL, + 0); + if (saved_dir_fname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto err; + } + /* Go to the parent directory to lock in memory. */ - if (vfs_ChDir(conn, priv_paths->parent_name.base_name) == -1) { + if (vfs_ChDir(conn, &priv_paths->parent_name) == -1) { status = map_nt_error_from_unix(errno); goto err; } @@ -1165,8 +1177,10 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, err: - if (saved_dir) { - vfs_ChDir(conn, saved_dir); + if (saved_dir_fname) { + vfs_ChDir(conn, saved_dir_fname); + TALLOC_FREE(saved_dir); + TALLOC_FREE(saved_dir_fname); } SAFE_FREE(resolved_name); if (!NT_STATUS_IS_OK(status)) { @@ -2014,6 +2028,8 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) char *parent_dir = NULL; const char *final_component = NULL; struct smb_filename *local_smb_fname = NULL; + struct smb_filename parent_dir_fname = {0}; + struct smb_filename saved_dir_fname = {0}; saved_dir = vfs_GetWd(talloc_tos(),fsp->conn); if (!saved_dir) { @@ -2024,6 +2040,10 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) return status; } + saved_dir_fname = (struct smb_filename) { + .base_name = saved_dir + }; + if (!parent_dirname(talloc_tos(), fsp->fsp_name->base_name, &parent_dir, @@ -2031,8 +2051,13 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) return NT_STATUS_NO_MEMORY; } + parent_dir_fname = (struct smb_filename) { + .base_name = parent_dir, + .flags = fsp->fsp_name->flags + }; + /* cd into the parent dir to pin it. */ - ret = vfs_ChDir(fsp->conn, parent_dir); + ret = vfs_ChDir(fsp->conn, &parent_dir_fname); if (ret == -1) { return map_nt_error_from_unix(errno); } @@ -2073,7 +2098,7 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) out: - vfs_ChDir(fsp->conn,saved_dir); + vfs_ChDir(fsp->conn, &saved_dir_fname); TALLOC_FREE(local_smb_fname); TALLOC_FREE(saved_dir); TALLOC_FREE(parent_dir); @@ -2099,10 +2124,11 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) return status; } -int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path) +int smb_vfs_call_chdir(struct vfs_handle_struct *handle, + const struct smb_filename *smb_fname) { VFS_FIND(chdir); - return handle->fns->chdir_fn(handle, path); + return handle->fns->chdir_fn(handle, smb_fname); } char *smb_vfs_call_getwd(struct vfs_handle_struct *handle) diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index 65a8e258d0d..f6d9d5b6be7 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -463,7 +463,8 @@ static NTSTATUS cmd_pathfunc(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int arg ret = SMB_VFS_UNLINK(vfs->conn, smb_fname); TALLOC_FREE(smb_fname); } else if (strcmp("chdir", argv[0]) == 0 ) { - ret = SMB_VFS_CHDIR(vfs->conn, argv[1]); + ret = SMB_VFS_CHDIR(vfs->conn, smb_fname); + TALLOC_FREE(smb_fname); } else { printf("%s: error=%d (invalid function name!)\n", argv[0], errno); return NT_STATUS_UNSUCCESSFUL; -- 2.34.1