diff options
author | Jeremy Allison <jra@samba.org> | 2017-06-29 14:32:47 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2017-07-01 03:07:11 +0200 |
commit | bd9285b19741128bae501b721d9e63dd9a9bd833 (patch) | |
tree | 7fd477f84fc8d1e072e3acb550157ab2da68b597 /source3 | |
parent | 6acb0d6ca08d72f776d3ba9dc934261a481aa737 (diff) | |
download | samba-bd9285b19741128bae501b721d9e63dd9a9bd833.tar.gz |
s3: VFS: Change SMB_VFS_GETWD to return struct smb_filename * instead of 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 <jra@samba.org>
Reviewed-by: Richard Sharpe <realrichardsharpe@gmail.com>
Diffstat (limited to 'source3')
-rw-r--r-- | source3/include/vfs.h | 12 | ||||
-rw-r--r-- | source3/include/vfs_macros.h | 8 | ||||
-rw-r--r-- | source3/modules/vfs_acl_common.c | 13 | ||||
-rw-r--r-- | source3/modules/vfs_ceph.c | 9 | ||||
-rw-r--r-- | source3/modules/vfs_default.c | 14 | ||||
-rw-r--r-- | source3/modules/vfs_dirsort.c | 10 | ||||
-rw-r--r-- | source3/modules/vfs_full_audit.c | 9 | ||||
-rw-r--r-- | source3/modules/vfs_glusterfs.c | 12 | ||||
-rw-r--r-- | source3/modules/vfs_netatalk.c | 25 | ||||
-rw-r--r-- | source3/modules/vfs_preopen.c | 3 | ||||
-rw-r--r-- | source3/modules/vfs_shadow_copy2.c | 12 | ||||
-rw-r--r-- | source3/modules/vfs_time_audit.c | 7 | ||||
-rw-r--r-- | source3/smbd/dir.c | 22 | ||||
-rw-r--r-- | source3/smbd/msdfs.c | 22 | ||||
-rw-r--r-- | source3/smbd/open.c | 43 | ||||
-rw-r--r-- | source3/smbd/proto.h | 2 | ||||
-rw-r--r-- | source3/smbd/service.c | 15 | ||||
-rw-r--r-- | source3/smbd/vfs.c | 120 | ||||
-rw-r--r-- | source3/torture/cmd_vfs.c | 8 | ||||
-rw-r--r-- | source3/torture/torture.c | 82 |
20 files changed, 259 insertions, 189 deletions
diff --git a/source3/include/vfs.h b/source3/include/vfs.h index f5ac5b5c82e..716e194a4ee 100644 --- a/source3/include/vfs.h +++ b/source3/include/vfs.h @@ -230,6 +230,10 @@ to const struct smb_filename * */ /* Version 37 - Change chdir from const char * to const struct smb_filename * */ +/* Version 37 - Change getwd from char * + to const struct smb_filename * */ +/* Version 37 - Change conn->cwd from char * + to struct smb_filename * */ #define SMB_VFS_INTERFACE_VERSION 37 @@ -419,7 +423,7 @@ typedef struct connection_struct { enum timestamp_set_resolution ts_res; char *connectpath; char *origpath; - char *cwd; /* Working directory. */ + struct smb_filename *cwd_fname; /* Working directory. */ struct vfs_handle_struct *vfs_handles; /* for the new plugins */ @@ -735,7 +739,8 @@ struct vfs_fn_pointers { gid_t gid); int (*chdir_fn)(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname); - char *(*getwd_fn)(struct vfs_handle_struct *handle); + struct smb_filename *(*getwd_fn)(struct vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx); int (*ntimes_fn)(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, struct smb_file_time *ft); @@ -1237,7 +1242,8 @@ int smb_vfs_call_lchown(struct vfs_handle_struct *handle, gid_t gid); 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); +struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle, + TALLOC_CTX *ctx); int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, const struct smb_filename *smb_fname, struct smb_file_time *ft); diff --git a/source3/include/vfs_macros.h b/source3/include/vfs_macros.h index 367009bad07..29f03389cce 100644 --- a/source3/include/vfs_macros.h +++ b/source3/include/vfs_macros.h @@ -271,10 +271,10 @@ #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) -#define SMB_VFS_NEXT_GETWD(handle) \ - smb_vfs_call_getwd((handle)->next) +#define SMB_VFS_GETWD(conn, ctx) \ + smb_vfs_call_getwd((conn)->vfs_handles, (ctx)) +#define SMB_VFS_NEXT_GETWD(handle, ctx) \ + smb_vfs_call_getwd((handle)->next, (ctx)) #define SMB_VFS_NTIMES(conn, path, ts) \ smb_vfs_call_ntimes((conn)->vfs_handles, (path), (ts)) diff --git a/source3/modules/vfs_acl_common.c b/source3/modules/vfs_acl_common.c index 3b054df2b7d..6abf1e312fb 100644 --- a/source3/modules/vfs_acl_common.c +++ b/source3/modules/vfs_acl_common.c @@ -1300,15 +1300,13 @@ static int acl_common_remove_object(vfs_handle_struct *handle, 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}; + struct smb_filename *saved_dir_fname = NULL; - saved_dir = vfs_GetWd(talloc_tos(),conn); - if (!saved_dir) { + saved_dir_fname = vfs_GetWd(talloc_tos(),conn); + if (saved_dir_fname == NULL) { saved_errno = errno; goto out; } - saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir, &final_component)) { @@ -1374,8 +1372,9 @@ static int acl_common_remove_object(vfs_handle_struct *handle, TALLOC_FREE(parent_dir); - if (saved_dir) { - vfs_ChDir(conn, &saved_dir_fname); + if (saved_dir_fname) { + vfs_ChDir(conn, saved_dir_fname); + TALLOC_FREE(saved_dir_fname); } if (saved_errno) { errno = saved_errno; diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c index 6b298a2e38f..7d3f4a7bbaa 100644 --- a/source3/modules/vfs_ceph.c +++ b/source3/modules/vfs_ceph.c @@ -949,11 +949,16 @@ static int cephwrap_chdir(struct vfs_handle_struct *handle, WRAP_RETURN(result); } -static char *cephwrap_getwd(struct vfs_handle_struct *handle) +static struct smb_filename *cephwrap_getwd(struct vfs_handle_struct *handle, + TALLOC_CTX *ctx) { const char *cwd = ceph_getcwd(handle->data); DBG_DEBUG("[CEPH] getwd(%p) = %s\n", handle, cwd); - return SMB_STRDUP(cwd); + return synthetic_smb_fname(ctx, + cwd, + NULL, + NULL, + 0); } static int strict_allocate_ftruncate(struct vfs_handle_struct *handle, files_struct *fsp, off_t len) diff --git a/source3/modules/vfs_default.c b/source3/modules/vfs_default.c index 7a2fae2156d..b01a0078180 100644 --- a/source3/modules/vfs_default.c +++ b/source3/modules/vfs_default.c @@ -2099,14 +2099,24 @@ static int vfswrap_chdir(vfs_handle_struct *handle, return result; } -static char *vfswrap_getwd(vfs_handle_struct *handle) +static struct smb_filename *vfswrap_getwd(vfs_handle_struct *handle, + TALLOC_CTX *ctx) { char *result; + struct smb_filename *smb_fname = NULL; START_PROFILE(syscall_getwd); result = sys_getwd(); END_PROFILE(syscall_getwd); - return result; + smb_fname = synthetic_smb_fname(ctx, + result, + NULL, + NULL, + 0); + if (smb_fname == NULL) { + SAFE_FREE(result); + } + return smb_fname; } /********************************************************************* diff --git a/source3/modules/vfs_dirsort.c b/source3/modules/vfs_dirsort.c index fc35186a402..c23f6f0152d 100644 --- a/source3/modules/vfs_dirsort.c +++ b/source3/modules/vfs_dirsort.c @@ -154,7 +154,15 @@ static DIR *dirsort_opendir(vfs_handle_struct *handle, } if (ISDOT(data->smb_fname->base_name)) { - data->smb_fname->base_name = vfs_GetWd(data, handle->conn); + struct smb_filename *cwd_fname = vfs_GetWd(data, handle->conn); + if (cwd_fname == NULL) { + TALLOC_FREE(data); + return NULL; + } + TALLOC_FREE(data->smb_fname->base_name); + data->smb_fname->base_name = talloc_move(data->smb_fname, + &cwd_fname->base_name); + TALLOC_FREE(cwd_fname); } /* Open the underlying directory and count the number of entries */ diff --git a/source3/modules/vfs_full_audit.c b/source3/modules/vfs_full_audit.c index 5d35c340371..51783245566 100644 --- a/source3/modules/vfs_full_audit.c +++ b/source3/modules/vfs_full_audit.c @@ -1521,14 +1521,15 @@ static int smb_full_audit_chdir(vfs_handle_struct *handle, return result; } -static char *smb_full_audit_getwd(vfs_handle_struct *handle) +static struct smb_filename *smb_full_audit_getwd(vfs_handle_struct *handle, + TALLOC_CTX *ctx) { - char *result; + struct smb_filename *result; - result = SMB_VFS_NEXT_GETWD(handle); + result = SMB_VFS_NEXT_GETWD(handle, ctx); do_log(SMB_VFS_OP_GETWD, (result != NULL), handle, "%s", - result == NULL? "" : result); + result == NULL? "" : result->base_name); return result; } diff --git a/source3/modules/vfs_glusterfs.c b/source3/modules/vfs_glusterfs.c index 833f093ac42..52539b36fd9 100644 --- a/source3/modules/vfs_glusterfs.c +++ b/source3/modules/vfs_glusterfs.c @@ -1076,10 +1076,12 @@ static int vfs_gluster_chdir(struct vfs_handle_struct *handle, return glfs_chdir(handle->data, smb_fname->base_name); } -static char *vfs_gluster_getwd(struct vfs_handle_struct *handle) +static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle, + TALLOC_CTX *ctx) { char *cwd; char *ret; + struct smb_filename *smb_fname = NULL; cwd = SMB_CALLOC_ARRAY(char, PATH_MAX); if (cwd == NULL) { @@ -1090,7 +1092,13 @@ static char *vfs_gluster_getwd(struct vfs_handle_struct *handle) if (ret == 0) { free(cwd); } - return ret; + smb_fname = synthetic_smb_fname(ctx, + ret, + NULL, + NULL, + 0); + free(cwd); + return smb_fname; } static int vfs_gluster_ntimes(struct vfs_handle_struct *handle, diff --git a/source3/modules/vfs_netatalk.c b/source3/modules/vfs_netatalk.c index 5715c6dd6ac..16c129de995 100644 --- a/source3/modules/vfs_netatalk.c +++ b/source3/modules/vfs_netatalk.c @@ -234,7 +234,7 @@ static int atalk_rmdir(struct vfs_handle_struct *handle, const char *path = smb_fname->base_name; char *dpath; - if (!handle->conn->cwd || !path) goto exit_rmdir; + if (!handle->conn->cwd_fname->base_name || !path) goto exit_rmdir; /* due to there is no way to change bDeleteVetoFiles variable * from this module, gotta use talloc stuff.. @@ -246,7 +246,7 @@ static int atalk_rmdir(struct vfs_handle_struct *handle, goto exit_rmdir; if (!(dpath = talloc_asprintf(ctx, "%s/%s%s", - handle->conn->cwd, path, add ? "/"APPLEDOUBLE : ""))) + handle->conn->cwd_fname->base_name, path, add ? "/"APPLEDOUBLE : ""))) goto exit_rmdir; atalk_rrmdir(ctx, dpath); @@ -277,7 +277,7 @@ static int atalk_rename(struct vfs_handle_struct *handle, return ret; } - if (atalk_build_paths(talloc_tos(), handle->conn->cwd, oldname, + if (atalk_build_paths(talloc_tos(), handle->conn->cwd_fname->base_name, oldname, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) goto exit_rename; @@ -338,7 +338,8 @@ static int atalk_unlink(struct vfs_handle_struct *handle, } } - if (atalk_build_paths(talloc_tos(), handle->conn->cwd, path, + if (atalk_build_paths(talloc_tos(), + handle->conn->cwd_fname->base_name, path, &adbl_path, &orig_path, &adbl_info, &orig_info) != 0) goto exit_unlink; @@ -375,7 +376,7 @@ static int atalk_chmod(struct vfs_handle_struct *handle, return ret; ret1 = atalk_build_paths(ctx, - handle->conn->cwd, + handle->conn->cwd_fname->base_name, smb_fname->base_name, &adbl_path, &orig_path, @@ -414,9 +415,10 @@ static int atalk_chown(struct vfs_handle_struct *handle, if (!(ctx = talloc_init("chown_file"))) return ret; - if (atalk_build_paths(ctx, handle->conn->cwd, smb_fname->base_name, - &adbl_path, &orig_path, - &adbl_info, &orig_info) != 0) + if (atalk_build_paths(ctx, handle->conn->cwd_fname->base_name, + smb_fname->base_name, + &adbl_path, &orig_path, + &adbl_info, &orig_info) != 0) goto exit_chown; if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) { @@ -450,9 +452,10 @@ static int atalk_lchown(struct vfs_handle_struct *handle, if (!(ctx = talloc_init("lchown_file"))) return ret; - if (atalk_build_paths(ctx, handle->conn->cwd, smb_fname->base_name, - &adbl_path, &orig_path, - &adbl_info, &orig_info) != 0) + if (atalk_build_paths(ctx, handle->conn->cwd_fname->base_name, + smb_fname->base_name, + &adbl_path, &orig_path, + &adbl_info, &orig_info) != 0) goto exit_lchown; if (!S_ISDIR(orig_info.st_ex_mode) && !S_ISREG(orig_info.st_ex_mode)) { diff --git a/source3/modules/vfs_preopen.c b/source3/modules/vfs_preopen.c index 12ec4763a62..18b01e6c05e 100644 --- a/source3/modules/vfs_preopen.c +++ b/source3/modules/vfs_preopen.c @@ -408,7 +408,8 @@ static int preopen_open(vfs_handle_struct *handle, TALLOC_FREE(state->template_fname); state->template_fname = talloc_asprintf( - state, "%s/%s", fsp->conn->cwd, smb_fname->base_name); + state, "%s/%s", + fsp->conn->cwd_fname->base_name, smb_fname->base_name); if (state->template_fname == NULL) { return res; diff --git a/source3/modules/vfs_shadow_copy2.c b/source3/modules/vfs_shadow_copy2.c index 4b5a7bccc97..b20213a698c 100644 --- a/source3/modules/vfs_shadow_copy2.c +++ b/source3/modules/vfs_shadow_copy2.c @@ -1523,19 +1523,19 @@ static void store_cwd_data(vfs_handle_struct *handle, const char *connectpath) { struct shadow_copy2_private *priv = NULL; - char *cwd = NULL; + struct smb_filename *cwd_fname = NULL; SMB_VFS_HANDLE_GET_DATA(handle, priv, struct shadow_copy2_private, return); TALLOC_FREE(priv->shadow_cwd); - cwd = SMB_VFS_NEXT_GETWD(handle); - if (cwd == NULL) { + cwd_fname = SMB_VFS_NEXT_GETWD(handle, talloc_tos()); + if (cwd_fname == NULL) { smb_panic("getwd failed\n"); } - DBG_DEBUG("shadow cwd = %s\n", cwd); - priv->shadow_cwd = talloc_strdup(priv, cwd); - SAFE_FREE(cwd); + DBG_DEBUG("shadow cwd = %s\n", cwd_fname->base_name); + priv->shadow_cwd = talloc_strdup(priv, cwd_fname->base_name); + TALLOC_FREE(cwd_fname); if (priv->shadow_cwd == NULL) { smb_panic("talloc failed\n"); } diff --git a/source3/modules/vfs_time_audit.c b/source3/modules/vfs_time_audit.c index 820de3ffa2c..22075e7ac16 100644 --- a/source3/modules/vfs_time_audit.c +++ b/source3/modules/vfs_time_audit.c @@ -1257,14 +1257,15 @@ static int smb_time_audit_chdir(vfs_handle_struct *handle, return result; } -static char *smb_time_audit_getwd(vfs_handle_struct *handle) +static struct smb_filename *smb_time_audit_getwd(vfs_handle_struct *handle, + TALLOC_CTX *mem_ctx) { - char *result; + struct smb_filename *result; struct timespec ts1,ts2; double timediff; clock_gettime_mono(&ts1); - result = SMB_VFS_NEXT_GETWD(handle); + result = SMB_VFS_NEXT_GETWD(handle, mem_ctx); clock_gettime_mono(&ts2); timediff = nsec_time_diff(&ts2,&ts1)*1.0e-9; diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c index 9391e3c827c..6b77409c73f 100644 --- a/source3/smbd/dir.c +++ b/source3/smbd/dir.c @@ -400,17 +400,14 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, { 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(talloc_tos(), conn); + struct smb_filename *saved_dir_fname = vfs_GetWd(talloc_tos(), conn); struct privilege_paths *priv_paths = req->priv_paths; int ret; - if (saved_dir == NULL) { + if (saved_dir_fname == NULL) { return NULL; } - saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; - if (vfs_ChDir(conn, smb_dname) == -1) { return NULL; } @@ -441,8 +438,8 @@ static struct smb_Dir *open_dir_with_privilege(connection_struct *conn, out: - vfs_ChDir(conn, &saved_dir_fname); - TALLOC_FREE(saved_dir); + vfs_ChDir(conn, saved_dir_fname); + TALLOC_FREE(saved_dir_fname); return dir_hnd; } @@ -1683,16 +1680,13 @@ 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); + struct smb_filename *saved_dir_fname = vfs_GetWd(ctx, conn); NTSTATUS status; - if (saved_dir == NULL) { + if (saved_dir_fname == NULL) { return NULL; } - saved_dir_fname = (struct smb_filename) { .base_name = saved_dir }; - if (vfs_ChDir(conn, smb_dname) == -1) { goto out; } @@ -1738,8 +1732,8 @@ static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx, out: - vfs_ChDir(conn, &saved_dir_fname); - TALLOC_FREE(saved_dir); + vfs_ChDir(conn, saved_dir_fname); + TALLOC_FREE(saved_dir_fname); return dir_hnd; } diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c index d87b9b9bace..3c23d745eee 100644 --- a/source3/smbd/msdfs.c +++ b/source3/smbd/msdfs.c @@ -403,8 +403,7 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, struct smb_filename **poldcwd_fname) { connection_struct *conn; - char *oldcwd = NULL; - struct smb_filename *smb_fname_oldcwd = NULL; + struct smb_filename *oldcwd_fname = NULL; struct smb_filename smb_fname_connectpath = {0}; NTSTATUS status = create_conn_struct(ctx, ev, @@ -421,25 +420,14 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, * user we will fail.... WTF ? JRA. */ - oldcwd = vfs_GetWd(ctx, conn); - if (oldcwd == NULL) { + 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_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 }; @@ -449,13 +437,13 @@ NTSTATUS create_conn_struct_cwd(TALLOC_CTX *ctx, 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); + TALLOC_FREE(oldcwd_fname); conn_free(conn); return status; } *pconn = conn; - *poldcwd_fname = smb_fname_oldcwd; + *poldcwd_fname = oldcwd_fname; return NT_STATUS_OK; } diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 031ba11f1d2..ac637ba7834 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -411,8 +411,7 @@ static int process_symlink_open(struct connection_struct *conn, int fd = -1; char *link_target = NULL; int link_len = -1; - char *oldwd = NULL; - struct smb_filename oldwd_fname = {0}; + struct smb_filename *oldwd_fname = NULL; size_t rootdir_len = 0; char *resolved_name = NULL; bool matched = false; @@ -484,13 +483,11 @@ static int process_symlink_open(struct connection_struct *conn, goto out; } - oldwd = vfs_GetWd(talloc_tos(), conn); - if (oldwd == NULL) { + oldwd_fname = vfs_GetWd(talloc_tos(), conn); + if (oldwd_fname == NULL) { 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_fname) == -1) { goto out; @@ -512,12 +509,12 @@ 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_fname); + if (oldwd_fname != NULL) { + int ret = vfs_ChDir(conn, oldwd_fname); if (ret == -1) { smb_panic("unable to get back to old directory\n"); } - TALLOC_FREE(oldwd); + TALLOC_FREE(oldwd_fname); } if (saved_errno != 0) { errno = saved_errno; @@ -541,8 +538,7 @@ static int non_widelink_open(struct connection_struct *conn, int fd = -1; struct smb_filename *smb_fname_rel = NULL; int saved_errno = 0; - char *oldwd = NULL; - struct smb_filename oldwd_fname = {0}; + struct smb_filename *oldwd_fname = NULL; char *parent_dir = NULL; struct smb_filename parent_dir_fname = {0}; const char *final_component = NULL; @@ -556,13 +552,11 @@ static int non_widelink_open(struct connection_struct *conn, parent_dir_fname = (struct smb_filename) { .base_name = parent_dir }; - oldwd = vfs_GetWd(talloc_tos(), conn); - if (oldwd == NULL) { + oldwd_fname = vfs_GetWd(talloc_tos(), conn); + if (oldwd_fname == NULL) { goto out; } - oldwd_fname = (struct smb_filename) { .base_name = oldwd }; - /* Pin parent directory in place. */ if (vfs_ChDir(conn, &parent_dir_fname) == -1) { goto out; @@ -644,12 +638,12 @@ static int non_widelink_open(struct connection_struct *conn, TALLOC_FREE(parent_dir); TALLOC_FREE(smb_fname_rel); - if (oldwd != NULL) { - int ret = vfs_ChDir(conn, &oldwd_fname); + if (oldwd_fname != NULL) { + int ret = vfs_ChDir(conn, oldwd_fname); if (ret == -1) { smb_panic("unable to get back to old directory\n"); } - TALLOC_FREE(oldwd); + TALLOC_FREE(oldwd_fname); } if (saved_errno != 0) { errno = saved_errno; @@ -837,8 +831,7 @@ static NTSTATUS change_dir_owner_to_parent(connection_struct *conn, { 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}; + struct smb_filename *saved_dir_fname = NULL; TALLOC_CTX *ctx = talloc_tos(); NTSTATUS status = NT_STATUS_OK; int ret; @@ -869,8 +862,8 @@ static NTSTATUS change_dir_owner_to_parent(connection_struct *conn, should work on any UNIX (thanks tridge :-). JRA. */ - saved_dir = vfs_GetWd(ctx,conn); - if (!saved_dir) { + saved_dir_fname = vfs_GetWd(ctx,conn); + if (!saved_dir_fname) { status = map_nt_error_from_unix(errno); DEBUG(0,("change_dir_owner_to_parent: failed to get " "current working directory. Error was %s\n", @@ -878,8 +871,6 @@ static 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, smb_dname) == -1) { status = map_nt_error_from_unix(errno); @@ -949,9 +940,9 @@ static NTSTATUS change_dir_owner_to_parent(connection_struct *conn, } chdir: - vfs_ChDir(conn, &smb_fname_saved_dir); + vfs_ChDir(conn, saved_dir_fname); out: - TALLOC_FREE(saved_dir); + TALLOC_FREE(saved_dir_fname); TALLOC_FREE(smb_fname_parent); TALLOC_FREE(smb_fname_cwd); return status; diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 4823e1170fc..7d641bdab19 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1232,7 +1232,7 @@ const char *vfs_readdirname(connection_struct *conn, void *p, SMB_STRUCT_STAT *sbuf, char **talloced); int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname); -char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn); +struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn); NTSTATUS check_reduced_name(connection_struct *conn, const char *cwd_name, const char *fname); diff --git a/source3/smbd/service.c b/source3/smbd/service.c index 47cd0fa19d5..ed739c9baf1 100644 --- a/source3/smbd/service.c +++ b/source3/smbd/service.c @@ -68,10 +68,17 @@ bool set_conn_connectpath(connection_struct *conn, const char *connectpath) talloc_free(conn->connectpath); conn->connectpath = destname; - /* Ensure conn->cwd is initialized - start as conn->connectpath. */ - TALLOC_FREE(conn->cwd); - conn->cwd = talloc_strdup(conn, conn->connectpath); - if (!conn->cwd) { + /* + * Ensure conn->cwd_fname is initialized. + * start as conn->connectpath. + */ + TALLOC_FREE(conn->cwd_fname); + conn->cwd_fname = synthetic_smb_fname(conn, + conn->connectpath, + NULL, + NULL, + 0); + if (conn->cwd_fname == NULL) { return false; } return true; diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 40c41ed27fc..5c4e9c37b30 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -881,9 +881,14 @@ int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname) LastDir = SMB_STRDUP(smb_fname->base_name); /* conn cache. */ - TALLOC_FREE(conn->cwd); - conn->cwd = vfs_GetWd(conn, conn); - DEBUG(4,("vfs_ChDir got %s\n",conn->cwd)); + TALLOC_FREE(conn->cwd_fname); + conn->cwd_fname = vfs_GetWd(conn, conn); + if (conn->cwd_fname == NULL) { + smb_panic("con->cwd getwd failed\n"); + /* NOTREACHED */ + return -1; + } + DEBUG(4,("vfs_ChDir got %s\n",conn->cwd_fname->base_name)); } return ret; } @@ -894,14 +899,13 @@ int vfs_ChDir(connection_struct *conn, const struct smb_filename *smb_fname) format. Note this can be called with conn == NULL. ********************************************************************/ -char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) +struct smb_filename *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { - char *current_dir = NULL; - char *result = NULL; - DATA_BLOB cache_value; + struct smb_filename *current_dir_fname = NULL; struct file_id key; struct smb_filename *smb_fname_dot = NULL; struct smb_filename *smb_fname_full = NULL; + struct smb_filename *result = NULL; if (!lp_getwd_cache()) { goto nocache; @@ -925,20 +929,13 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); - if (!memcache_lookup(smbd_memcache(), GETWD_CACHE, - data_blob_const(&key, sizeof(key)), - &cache_value)) { - goto nocache; - } - - SMB_ASSERT((cache_value.length > 0) - && (cache_value.data[cache_value.length-1] == '\0')); + smb_fname_full = (struct smb_filename *)memcache_lookup_talloc( + smbd_memcache(), + GETWD_CACHE, + data_blob_const(&key, sizeof(key))); - smb_fname_full = synthetic_smb_fname(ctx, (char *)cache_value.data, - NULL, NULL, 0); if (smb_fname_full == NULL) { - errno = ENOMEM; - goto out; + goto nocache; } if ((SMB_VFS_STAT(conn, smb_fname_full) == 0) && @@ -947,8 +944,10 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) (S_ISDIR(smb_fname_dot->st.st_ex_mode))) { /* * Ok, we're done + * Note: smb_fname_full is owned by smbd_memcache() + * so we must make a copy to return. */ - result = talloc_strdup(ctx, smb_fname_full->base_name); + result = cp_smb_filename(ctx, smb_fname_full); if (result == NULL) { errno = ENOMEM; } @@ -963,8 +962,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) * systems, or the not quite so bad getwd. */ - current_dir = SMB_VFS_GETWD(conn); - if (current_dir == NULL) { + current_dir_fname = SMB_VFS_GETWD(conn, ctx); + if (current_dir_fname == NULL) { DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n", strerror(errno))); goto out; @@ -973,21 +972,39 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) if (lp_getwd_cache() && VALID_STAT(smb_fname_dot->st)) { key = vfs_file_id_from_sbuf(conn, &smb_fname_dot->st); - memcache_add(smbd_memcache(), GETWD_CACHE, - data_blob_const(&key, sizeof(key)), - data_blob_const(current_dir, - strlen(current_dir)+1)); - } + /* + * smbd_memcache() will own current_dir_fname after the + * memcache_add_talloc call, so we must make + * a copy on ctx to return. + */ + result = cp_smb_filename(ctx, current_dir_fname); + if (result == NULL) { + errno = ENOMEM; + } - result = talloc_strdup(ctx, current_dir); - if (result == NULL) { - errno = ENOMEM; + /* + * Ensure the memory going into the cache + * doesn't have a destructor so it can be + * cleanly freed. + */ + talloc_set_destructor(current_dir_fname, NULL); + + memcache_add_talloc(smbd_memcache(), + GETWD_CACHE, + data_blob_const(&key, sizeof(key)), + ¤t_dir_fname); + /* current_dir_fname is now == NULL here. */ + } else { + /* current_dir_fname is already allocated on ctx. */ + result = current_dir_fname; } out: TALLOC_FREE(smb_fname_dot); - TALLOC_FREE(smb_fname_full); - SAFE_FREE(current_dir); + /* + * Don't free current_dir_fname here. It's either been moved + * to the memcache or is being returned in result. + */ return result; } @@ -1009,7 +1026,6 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, char *dir_name = NULL; 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; @@ -1045,23 +1061,12 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, goto err; } /* Remember where we were. */ - saved_dir = vfs_GetWd(ctx, conn); - if (!saved_dir) { + saved_dir_fname = vfs_GetWd(ctx, conn); + if (!saved_dir_fname) { status = map_nt_error_from_unix(errno); 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) == -1) { status = map_nt_error_from_unix(errno); goto err; @@ -1177,9 +1182,8 @@ NTSTATUS check_reduced_name_with_privilege(connection_struct *conn, err: - if (saved_dir_fname) { + if (saved_dir_fname != NULL) { vfs_ChDir(conn, saved_dir_fname); - TALLOC_FREE(saved_dir); TALLOC_FREE(saved_dir_fname); } SAFE_FREE(resolved_name); @@ -2024,15 +2028,14 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) * and always act using lchown to ensure we * don't deref any symbolic links. */ - char *saved_dir = NULL; 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}; + struct smb_filename *saved_dir_fname = NULL; - saved_dir = vfs_GetWd(talloc_tos(),fsp->conn); - if (!saved_dir) { + saved_dir_fname = vfs_GetWd(talloc_tos(),fsp->conn); + if (!saved_dir_fname) { status = map_nt_error_from_unix(errno); DEBUG(0,("vfs_chown_fsp: failed to get " "current working directory. Error was %s\n", @@ -2040,10 +2043,6 @@ 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, @@ -2098,9 +2097,9 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) out: - vfs_ChDir(fsp->conn, &saved_dir_fname); + vfs_ChDir(fsp->conn, saved_dir_fname); TALLOC_FREE(local_smb_fname); - TALLOC_FREE(saved_dir); + TALLOC_FREE(saved_dir_fname); TALLOC_FREE(parent_dir); return status; @@ -2131,10 +2130,11 @@ int smb_vfs_call_chdir(struct vfs_handle_struct *handle, return handle->fns->chdir_fn(handle, smb_fname); } -char *smb_vfs_call_getwd(struct vfs_handle_struct *handle) +struct smb_filename *smb_vfs_call_getwd(struct vfs_handle_struct *handle, + TALLOC_CTX *ctx) { VFS_FIND(getwd); - return handle->fns->getwd_fn(handle); + return handle->fns->getwd_fn(handle, ctx); } int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, diff --git a/source3/torture/cmd_vfs.c b/source3/torture/cmd_vfs.c index f6d9d5b6be7..fd09df9bcd6 100644 --- a/source3/torture/cmd_vfs.c +++ b/source3/torture/cmd_vfs.c @@ -1057,14 +1057,14 @@ static NTSTATUS cmd_fchown(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, static NTSTATUS cmd_getwd(struct vfs_state *vfs, TALLOC_CTX *mem_ctx, int argc, const char **argv) { - char *buf = SMB_VFS_GETWD(vfs->conn); - if (buf == NULL) { + struct smb_filename *smb_fname = SMB_VFS_GETWD(vfs->conn, talloc_tos()); + if (smb_fname == NULL) { printf("getwd: error=%d (%s)\n", errno, strerror(errno)); return NT_STATUS_UNSUCCESSFUL; } - printf("getwd: %s\n", buf); - SAFE_FREE(buf); + printf("getwd: %s\n", smb_fname->base_name); + TALLOC_FREE(smb_fname); return NT_STATUS_OK; } diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 10e450ee4a7..6959b715b00 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -10580,15 +10580,25 @@ static bool data_blob_equal(DATA_BLOB a, DATA_BLOB b) static bool run_local_memcache(int dummy) { struct memcache *cache; - DATA_BLOB k1, k2; - DATA_BLOB d1, d2, d3; - DATA_BLOB v1, v2, v3; + DATA_BLOB k1, k2, k3; + DATA_BLOB d1, d3; + DATA_BLOB v1, v3; TALLOC_CTX *mem_ctx; + char *ptr1 = NULL; + char *ptr2 = NULL; + char *str1, *str2; size_t size1, size2; bool ret = false; + mem_ctx = talloc_init("foo"); + if (mem_ctx == NULL) { + return false; + } + + /* STAT_CACHE TESTS */ + cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100); if (cache == NULL) { @@ -10597,14 +10607,13 @@ static bool run_local_memcache(int dummy) } d1 = data_blob_const("d1", 2); - d2 = data_blob_const("d2", 2); d3 = data_blob_const("d3", 2); k1 = data_blob_const("d1", 2); k2 = data_blob_const("d2", 2); + k3 = data_blob_const("d3", 2); memcache_add(cache, STAT_CACHE, k1, d1); - memcache_add(cache, GETWD_CACHE, k2, d2); if (!memcache_lookup(cache, STAT_CACHE, k1, &v1)) { printf("could not find k1\n"); @@ -10614,40 +10623,79 @@ static bool run_local_memcache(int dummy) return false; } - if (!memcache_lookup(cache, GETWD_CACHE, k2, &v2)) { - printf("could not find k2\n"); + memcache_add(cache, STAT_CACHE, k1, d3); + + if (!memcache_lookup(cache, STAT_CACHE, k1, &v3)) { + printf("could not find replaced k1\n"); return false; } - if (!data_blob_equal(d2, v2)) { + if (!data_blob_equal(d3, v3)) { return false; } - memcache_add(cache, STAT_CACHE, k1, d3); + TALLOC_FREE(cache); - if (!memcache_lookup(cache, STAT_CACHE, k1, &v3)) { - printf("could not find replaced k1\n"); + /* GETWD_CACHE TESTS */ + str1 = talloc_strdup(mem_ctx, "string1"); + if (str1 == NULL) { return false; } - if (!data_blob_equal(d3, v3)) { + ptr2 = str1; /* Keep an alias for comparison. */ + + str2 = talloc_strdup(mem_ctx, "string2"); + if (str2 == NULL) { + return false; + } + + cache = memcache_init(NULL, sizeof(void *) == 8 ? 200 : 100); + if (cache == NULL) { + printf("memcache_init failed\n"); + return false; + } + + memcache_add_talloc(cache, GETWD_CACHE, k2, &str1); + /* str1 == NULL now. */ + ptr1 = memcache_lookup_talloc(cache, GETWD_CACHE, k2); + if (ptr1 == NULL) { + printf("could not find k2\n"); + return false; + } + if (ptr1 != ptr2) { + printf("fetch of k2 got wrong string\n"); return false; } - memcache_add(cache, GETWD_CACHE, k1, d1); + /* Add a blob to ensure k2 gets purged. */ + d3 = data_blob_talloc_zero(mem_ctx, 180); + memcache_add(cache, STAT_CACHE, k3, d3); - if (memcache_lookup(cache, GETWD_CACHE, k2, &v2)) { + ptr2 = memcache_lookup_talloc(cache, GETWD_CACHE, k2); + if (ptr2 != NULL) { printf("Did find k2, should have been purged\n"); return false; } TALLOC_FREE(cache); - - cache = memcache_init(NULL, 0); + TALLOC_FREE(mem_ctx); mem_ctx = talloc_init("foo"); + if (mem_ctx == NULL) { + return false; + } + + cache = memcache_init(NULL, 0); + if (cache == NULL) { + return false; + } str1 = talloc_strdup(mem_ctx, "string1"); + if (str1 == NULL) { + return false; + } str2 = talloc_strdup(mem_ctx, "string2"); - + if (str2 == NULL) { + return false; + } memcache_add_talloc(cache, SINGLETON_CACHE_TALLOC, data_blob_string_const("torture"), &str1); size1 = talloc_total_size(cache); |