diff options
Diffstat (limited to 'source3/smbd/vfs.c')
-rw-r--r-- | source3/smbd/vfs.c | 87 |
1 files changed, 49 insertions, 38 deletions
diff --git a/source3/smbd/vfs.c b/source3/smbd/vfs.c index 3b482e7f0c..7be3867267 100644 --- a/source3/smbd/vfs.c +++ b/source3/smbd/vfs.c @@ -183,7 +183,7 @@ bool vfs_init_custom(connection_struct *conn, const char *vfs_object) DEBUGADD(5,("Successfully loaded vfs module [%s] with the new modules system\n", vfs_object)); - handle = TALLOC_ZERO_P(conn, vfs_handle_struct); + handle = talloc_zero(conn, vfs_handle_struct); if (!handle) { DEBUG(0,("TALLOC_ZERO() failed!\n")); goto fail; @@ -795,7 +795,7 @@ int vfs_ChDir(connection_struct *conn, const char *path) char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) { - char s[PATH_MAX+1]; + char *current_dir = NULL; char *result = NULL; DATA_BLOB cache_value; struct file_id key; @@ -803,8 +803,6 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) struct smb_filename *smb_fname_full = NULL; NTSTATUS status; - *s = 0; - if (!lp_getwd_cache()) { goto nocache; } @@ -866,7 +864,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) * systems, or the not quite so bad getwd. */ - if (!SMB_VFS_GETWD(conn,s)) { + current_dir = SMB_VFS_GETWD(conn); + if (current_dir == NULL) { DEBUG(0, ("vfs_GetWd: SMB_VFS_GETWD call failed: %s\n", strerror(errno))); goto out; @@ -877,10 +876,11 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) memcache_add(smbd_memcache(), GETWD_CACHE, data_blob_const(&key, sizeof(key)), - data_blob_const(s, strlen(s)+1)); + data_blob_const(current_dir, + strlen(current_dir)+1)); } - result = talloc_strdup(ctx, s); + result = talloc_strdup(ctx, current_dir); if (result == NULL) { errno = ENOMEM; } @@ -888,6 +888,7 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) out: TALLOC_FREE(smb_fname_dot); TALLOC_FREE(smb_fname_full); + SAFE_FREE(current_dir); return result; } @@ -899,6 +900,8 @@ char *vfs_GetWd(TALLOC_CTX *ctx, connection_struct *conn) NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) { char *resolved_name = NULL; + bool allow_symlinks = true; + bool allow_widelinks = false; DEBUG(3,("check_reduced_name [%s] [%s]\n", fname, conn->connectpath)); @@ -973,9 +976,13 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) return NT_STATUS_OBJECT_NAME_INVALID; } - /* Check for widelinks allowed. */ - if (!lp_widelinks(SNUM(conn))) { + allow_widelinks = lp_widelinks(SNUM(conn)); + allow_symlinks = lp_symlinks(SNUM(conn)); + + /* Common widelinks and symlinks checks. */ + if (!allow_widelinks || !allow_symlinks) { const char *conn_rootdir; + size_t rootdir_len; conn_rootdir = SMB_VFS_CONNECTPATH(conn, fname); if (conn_rootdir == NULL) { @@ -985,8 +992,9 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) return NT_STATUS_ACCESS_DENIED; } + rootdir_len = strlen(conn_rootdir); if (strncmp(conn_rootdir, resolved_name, - strlen(conn_rootdir)) != 0) { + rootdir_len) != 0) { DEBUG(2, ("check_reduced_name: Bad access " "attempt: %s is a symlink outside the " "share path\n", fname)); @@ -995,35 +1003,38 @@ NTSTATUS check_reduced_name(connection_struct *conn, const char *fname) SAFE_FREE(resolved_name); return NT_STATUS_ACCESS_DENIED; } - } - /* Check if we are allowing users to follow symlinks */ - /* Patch from David Clerc <David.Clerc@cui.unige.ch> - University of Geneva */ + /* Extra checks if all symlinks are disallowed. */ + if (!allow_symlinks) { + /* fname can't have changed in resolved_path. */ + const char *p = &resolved_name[rootdir_len]; -#ifdef S_ISLNK - if (!lp_symlinks(SNUM(conn))) { - struct smb_filename *smb_fname = NULL; - NTSTATUS status; + /* *p can be '\0' if fname was "." */ + if (*p == '\0' && ISDOT(fname)) { + goto out; + } - status = create_synthetic_smb_fname(talloc_tos(), fname, NULL, - NULL, &smb_fname); - if (!NT_STATUS_IS_OK(status)) { - SAFE_FREE(resolved_name); - return status; + if (*p != '/') { + DEBUG(2, ("check_reduced_name: logic error (%c) " + "in resolved_name: %s\n", + *p, + fname)); + SAFE_FREE(resolved_name); + return NT_STATUS_ACCESS_DENIED; + } + + p++; + if (strcmp(fname, p)!=0) { + DEBUG(2, ("check_reduced_name: Bad access " + "attempt: %s is a symlink\n", + fname)); + SAFE_FREE(resolved_name); + return NT_STATUS_ACCESS_DENIED; + } } + } - if ( (SMB_VFS_LSTAT(conn, smb_fname) != -1) && - (S_ISLNK(smb_fname->st.st_ex_mode)) ) { - SAFE_FREE(resolved_name); - DEBUG(3,("check_reduced_name: denied: file path name " - "%s is a symlink\n",resolved_name)); - TALLOC_FREE(smb_fname); - return NT_STATUS_ACCESS_DENIED; - } - TALLOC_FREE(smb_fname); - } -#endif + out: DEBUG(3,("check_reduced_name: %s reduced to %s\n", fname, resolved_name)); @@ -1164,7 +1175,7 @@ int smb_vfs_call_set_quota(struct vfs_handle_struct *handle, int smb_vfs_call_get_shadow_copy_data(struct vfs_handle_struct *handle, struct files_struct *fsp, - SHADOW_COPY_DATA *shadow_copy_data, + struct shadow_copy_data *shadow_copy_data, bool labels) { VFS_FIND(get_shadow_copy_data); @@ -1496,7 +1507,7 @@ NTSTATUS vfs_chown_fsp(files_struct *fsp, uid_t uid, gid_t gid) } ZERO_STRUCT(local_fname); - local_fname.base_name = CONST_DISCARD(char *,final_component); + local_fname.base_name = discard_const_p(char, final_component); /* Must use lstat here. */ ret = SMB_VFS_LSTAT(fsp->conn, &local_fname); @@ -1543,10 +1554,10 @@ int smb_vfs_call_chdir(struct vfs_handle_struct *handle, const char *path) return handle->fns->chdir(handle, path); } -char *smb_vfs_call_getwd(struct vfs_handle_struct *handle, char *buf) +char *smb_vfs_call_getwd(struct vfs_handle_struct *handle) { VFS_FIND(getwd); - return handle->fns->getwd(handle, buf); + return handle->fns->getwd(handle); } int smb_vfs_call_ntimes(struct vfs_handle_struct *handle, |