#include "includes.h"
#include "system/filesys.h"
+#include "lib/util/server_id.h"
#include "printing.h"
#include "smbd/smbd.h"
#include "smbd/globals.h"
return NT_STATUS_OK;
}
- status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+ status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
(SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL), talloc_tos(), &sd);
* Samba 3.6 and earlier granted execute access even
* if the ACL did not contain execute rights.
* Samba 4.0 is more correct and checks it.
- * The compatibilty mode allows to skip this check
+ * The compatibilty mode allows one to skip this check
* to smoothen upgrades.
*/
if (lp_acl_allow_execute_always(SNUM(conn))) {
return NT_STATUS_OK;
}
-static NTSTATUS check_parent_access(struct connection_struct *conn,
+NTSTATUS check_parent_access(struct connection_struct *conn,
struct smb_filename *smb_fname,
uint32_t access_mask)
{
char *parent_dir = NULL;
struct security_descriptor *parent_sd = NULL;
uint32_t access_granted = 0;
+ struct smb_filename *parent_smb_fname = NULL;
if (!parent_dirname(talloc_tos(),
smb_fname->base_name,
return NT_STATUS_NO_MEMORY;
}
+ parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+ parent_dir,
+ NULL,
+ NULL,
+ smb_fname->flags);
+ if (parent_smb_fname == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
if (get_current_uid(conn) == (uid_t)0) {
/* I'm sorry sir, I didn't know you were root... */
DEBUG(10,("check_parent_access: root override "
}
status = SMB_VFS_GET_NT_ACL(conn,
- parent_dir,
+ parent_smb_fname,
SECINFO_DACL,
talloc_tos(),
&parent_sd);
* client should be doing this.
*/
- if (fsp->posix_open || !lp_follow_symlinks(SNUM(conn))) {
+ if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
flags |= O_NOFOLLOW;
}
#endif
struct smb_filename *smb_fname_parent;
int ret;
- smb_fname_parent = synthetic_smb_fname(talloc_tos(), inherit_from_dir,
- NULL, NULL);
+ smb_fname_parent = synthetic_smb_fname(talloc_tos(),
+ inherit_from_dir,
+ NULL,
+ NULL,
+ 0);
if (smb_fname_parent == NULL) {
return;
}
NTSTATUS status = NT_STATUS_OK;
int ret;
- smb_fname_parent = synthetic_smb_fname(ctx, inherit_from_dir,
- NULL, NULL);
+ smb_fname_parent = synthetic_smb_fname(ctx,
+ inherit_from_dir,
+ NULL,
+ NULL,
+ 0);
if (smb_fname_parent == NULL) {
return NT_STATUS_NO_MEMORY;
}
goto chdir;
}
- smb_fname_cwd = synthetic_smb_fname(ctx, ".", NULL, NULL);
+ smb_fname_cwd = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
if (smb_fname_cwd == NULL) {
status = NT_STATUS_NO_MEMORY;
goto chdir;
}
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);
bool *file_created)
{
NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ NTSTATUS retry_status;
bool file_existed = VALID_STAT(fsp->fsp_name->st);
+ int curr_flags;
*file_created = false;
* we can never call O_CREAT without O_EXCL. So if
* we think the file existed, try without O_CREAT|O_EXCL.
* If we think the file didn't exist, try with
- * O_CREAT|O_EXCL. Keep bouncing between these two
- * requests until either the file is created, or
- * opened. Either way, we keep going until we get
- * a returnable result (error, or open/create).
+ * O_CREAT|O_EXCL.
+ *
+ * The big problem here is dangling symlinks. Opening
+ * without O_NOFOLLOW means both bad symlink
+ * and missing path return -1, ENOENT from open(). As POSIX
+ * is pathname based it's not possible to tell
+ * the difference between these two cases in a
+ * non-racy way, so change to try only two attempts before
+ * giving up.
+ *
+ * We don't have this problem for the O_NOFOLLOW
+ * case as it just returns NT_STATUS_OBJECT_PATH_NOT_FOUND
+ * mapped from the ELOOP POSIX error.
*/
- while(1) {
- int curr_flags = flags;
+ curr_flags = flags;
- if (file_existed) {
- /* Just try open, do not create. */
- curr_flags &= ~(O_CREAT);
- status = fd_open(conn, fsp, curr_flags, mode);
- if (NT_STATUS_EQUAL(status,
- NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
- /*
- * Someone deleted it in the meantime.
- * Retry with O_EXCL.
- */
- file_existed = false;
- DEBUG(10,("fd_open_atomic: file %s existed. "
- "Retry.\n",
- smb_fname_str_dbg(fsp->fsp_name)));
- continue;
- }
- } else {
- /* Try create exclusively, fail if it exists. */
- curr_flags |= O_EXCL;
- status = fd_open(conn, fsp, curr_flags, mode);
- if (NT_STATUS_EQUAL(status,
- NT_STATUS_OBJECT_NAME_COLLISION)) {
- /*
- * Someone created it in the meantime.
- * Retry without O_CREAT.
- */
- file_existed = true;
- DEBUG(10,("fd_open_atomic: file %s "
- "did not exist. Retry.\n",
- smb_fname_str_dbg(fsp->fsp_name)));
- continue;
- }
- if (NT_STATUS_IS_OK(status)) {
- /*
- * Here we've opened with O_CREAT|O_EXCL
- * and got success. We *know* we created
- * this file.
- */
- *file_created = true;
- }
+ if (file_existed) {
+ curr_flags &= ~(O_CREAT);
+ retry_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ } else {
+ curr_flags |= O_EXCL;
+ retry_status = NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ status = fd_open(conn, fsp, curr_flags, mode);
+ if (NT_STATUS_IS_OK(status)) {
+ if (!file_existed) {
+ *file_created = true;
}
- /* Create is done, or failed. */
- break;
+ return NT_STATUS_OK;
}
+ if (!NT_STATUS_EQUAL(status, retry_status)) {
+ return status;
+ }
+
+ curr_flags = flags;
+
+ /*
+ * Keep file_existed up to date for clarity.
+ */
+ if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+ file_existed = false;
+ curr_flags |= O_EXCL;
+ DBG_DEBUG("file %s did not exist. Retry.\n",
+ smb_fname_str_dbg(fsp->fsp_name));
+ } else {
+ file_existed = true;
+ curr_flags &= ~(O_CREAT);
+ DBG_DEBUG("file %s existed. Retry.\n",
+ smb_fname_str_dbg(fsp->fsp_name));
+ }
+
+ status = fd_open(conn, fsp, curr_flags, mode);
+
+ if (NT_STATUS_IS_OK(status) && (!file_existed)) {
+ *file_created = true;
+ }
+
return status;
}
const char *parent_dir,
int flags,
mode_t unx_mode,
- uint32 access_mask, /* client requested access mask. */
- uint32 open_access_mask, /* what we're actually using in the open. */
+ uint32_t access_mask, /* client requested access mask. */
+ uint32_t open_access_mask, /* what we're actually using in the open. */
bool *p_file_created)
{
struct smb_filename *smb_fname = fsp->fsp_name;
wild = smb_fname->base_name;
}
if ((local_flags & O_CREAT) && !file_existed &&
+ !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
ms_has_wild(wild)) {
return NT_STATUS_OBJECT_NAME_INVALID;
}
return status;
}
+ if (local_flags & O_NONBLOCK) {
+ /*
+ * GPFS can return ETIMEDOUT for pread on
+ * nonblocking file descriptors when files
+ * migrated to tape need to be recalled. I
+ * could imagine this happens elsehwere
+ * too. With blocking file descriptors this
+ * does not happen.
+ */
+ ret = set_blocking(fsp->fh->fd, true);
+ if (ret == -1) {
+ status = map_nt_error_from_unix(errno);
+ DBG_WARNING("Could not set fd to blocking: "
+ "%s\n", strerror(errno));
+ fd_close(fsp);
+ return status;
+ }
+ }
+
ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
if (ret == -1) {
/* If we have an fd, this stat should succeed. */
}
/* Change the owner if required. */
- if (lp_inherit_owner(SNUM(conn))) {
+ if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) {
change_file_owner_to_parent(conn, parent_dir,
fsp);
need_re_stat = true;
access_mask);
if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
- fsp->posix_open &&
+ (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
S_ISLNK(smb_fname->st.st_ex_mode)) {
/* This is a POSIX stat open for delete
* or rename on a symlink that points
****************************************************************************/
static bool share_conflict(struct share_mode_entry *entry,
- uint32 access_mask,
- uint32 share_access)
+ uint32_t access_mask,
+ uint32_t share_access)
{
DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "
"entry->share_access = 0x%x, "
"share entry with an open file\n");
}
- if (((uint16)fsp->oplock_type) != share_entry->op_type) {
+ if (((uint16_t)fsp->oplock_type) != share_entry->op_type) {
goto panic;
}
}
#endif
-bool is_stat_open(uint32 access_mask)
+bool is_stat_open(uint32_t access_mask)
{
const uint32_t stat_open_bits =
(SYNCHRONIZE_ACCESS|
static NTSTATUS open_mode_check(connection_struct *conn,
struct share_mode_lock *lck,
- uint32 access_mask,
- uint32 share_access)
+ uint32_t access_mask,
+ uint32_t share_access)
{
- int i;
+ uint32_t i;
if(lck->data->num_share_modes == 0) {
return NT_STATUS_OK;
/* Overload entry->op_type */
/*
- * This is a cut from uint32 to uint16, but so far only the lower 3
+ * This is a cut from uint32_t to uint16_t, but so far only the lower 3
* bits (LEASE_WRITE/HANDLE/READ are used anyway.
*/
SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET, break_to);
status = messaging_send_buf(msg_ctx, exclusive->pid,
MSG_SMB_BREAK_REQUEST,
- (uint8 *)msg, sizeof(msg));
+ (uint8_t *)msg, sizeof(msg));
if (!NT_STATUS_IS_OK(status)) {
DEBUG(3, ("Could not send oplock break message: %s\n",
nt_errstr(status)));
/*
* we'll decide about SMB2_LEASE_READ later.
*
- * Maybe the break will be defered
+ * Maybe the break will be deferred
*/
break_to &= ~SMB2_LEASE_HANDLE;
}
DEBUG(10, ("defering mid %llu\n",
(unsigned long long)req->mid));
- watch_req = dbwrap_record_watch_send(
+ watch_req = dbwrap_watched_watch_send(
watch_state, req->sconn->ev_ctx, lck->data->record,
- req->sconn->msg_ctx);
+ (struct server_id){0});
if (watch_req == NULL) {
exit_server("Could not watch share mode record");
}
NTSTATUS status;
bool ret;
- status = dbwrap_record_watch_recv(req, talloc_tos(), NULL);
+ status = dbwrap_watched_watch_recv(req, talloc_tos(), NULL, NULL,
+ NULL);
TALLOC_FREE(req);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
+ DEBUG(5, ("dbwrap_watched_watch_recv returned %s\n",
nt_errstr(status)));
/*
* Even if it failed, retry anyway. TODO: We need a way to
****************************************************************************/
static bool open_match_attributes(connection_struct *conn,
- uint32 old_dos_attr,
- uint32 new_dos_attr,
+ uint32_t old_dos_attr,
+ uint32_t new_dos_attr,
mode_t existing_unx_mode,
mode_t new_unx_mode,
mode_t *returned_unx_mode)
{
- uint32 noarch_old_dos_attr, noarch_new_dos_attr;
+ uint32_t noarch_old_dos_attr, noarch_new_dos_attr;
noarch_old_dos_attr = (old_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
noarch_new_dos_attr = (new_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
files_struct *fsp_to_dup_into,
const struct smb_filename *smb_fname,
struct file_id id,
- uint16 file_pid,
+ uint16_t file_pid,
uint64_t vuid,
- uint32 access_mask,
- uint32 share_access,
- uint32 create_options)
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_options)
{
files_struct *fsp;
return NT_STATUS_OK;
}
- status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+ status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
(SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL),
uint32_t orig_access_mask = access_mask;
uint32_t rejected_share_access;
+ if (access_mask & SEC_MASK_INVALID) {
+ DBG_DEBUG("access_mask [%8x] contains invalid bits\n",
+ access_mask);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+
/*
* Convert GENERIC bits to specific bits.
*/
}
static int calculate_open_access_flags(uint32_t access_mask,
- int oplock_request,
uint32_t private_flags)
{
bool need_write, need_read;
static NTSTATUS open_file_ntcreate(connection_struct *conn,
struct smb_request *req,
- uint32 access_mask, /* access bits (FILE_READ_DATA etc.) */
- uint32 share_access, /* share constants (FILE_SHARE_READ etc) */
- uint32 create_disposition, /* FILE_OPEN_IF etc. */
- uint32 create_options, /* options such as delete on close. */
- uint32 new_dos_attributes, /* attributes used for new file. */
+ uint32_t access_mask, /* access bits (FILE_READ_DATA etc.) */
+ uint32_t share_access, /* share constants (FILE_SHARE_READ etc) */
+ uint32_t create_disposition, /* FILE_OPEN_IF etc. */
+ uint32_t create_options, /* options such as delete on close. */
+ uint32_t new_dos_attributes, /* attributes used for new file. */
int oplock_request, /* internal Samba oplock codes. */
struct smb2_lease *lease,
/* Information (FILE_EXISTS etc.) */
mode_t new_unx_mode = (mode_t)0;
mode_t unx_mode = (mode_t)0;
int info;
- uint32 existing_dos_attributes = 0;
+ uint32_t existing_dos_attributes = 0;
struct timeval request_time = timeval_zero();
struct share_mode_lock *lck = NULL;
- uint32 open_access_mask = access_mask;
+ uint32_t open_access_mask = access_mask;
NTSTATUS status;
char *parent_dir;
SMB_STRUCT_STAT saved_stat = smb_fname->st;
if (!posix_open) {
new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
if (file_existed) {
- existing_dos_attributes = dos_mode(conn, smb_fname);
+ /*
+ * Only use strored DOS attributes for checks
+ * against requested attributes (below via
+ * open_match_attributes()), cf bug #11992
+ * for details. -slow
+ */
+ uint32_t attr = 0;
+
+ status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &attr);
+ if (NT_STATUS_IS_OK(status)) {
+ existing_dos_attributes = attr;
+ }
}
}
}
/* this is for OS/2 long file names - say we don't support them */
- if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) {
+ if (req != NULL && !req->posix_pathnames &&
+ strstr(smb_fname->base_name,".+,;=[].")) {
/* OS/2 Workplace shell fix may be main code stream in a later
* release. */
DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not "
* mean the same thing under DOS and Unix.
*/
- flags = calculate_open_access_flags(access_mask, oplock_request,
- private_flags);
+ flags = calculate_open_access_flags(access_mask, private_flags);
/*
* Currently we only look at FILE_WRITE_THROUGH for create options.
fsp->access_mask = open_access_mask; /* We change this to the
* requested access_mask after
* the open is done. */
- fsp->posix_open = posix_open;
+ if (posix_open) {
+ fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
+ }
if (timeval_is_zero(&request_time)) {
request_time = fsp->open_time;
if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_NETWORK_BUSY)) {
struct deferred_open_record state;
+ bool delay;
/*
- * EWOULDBLOCK/EAGAIN maps to NETWORK_BUSY.
+ * This handles the kernel oplock case:
+ *
+ * the file has an active kernel oplock and the open() returned
+ * EWOULDBLOCK/EAGAIN which maps to NETWORK_BUSY.
+ *
+ * "Samba locking.tdb oplocks" are handled below after acquiring
+ * the sharemode lock with get_share_mode_lock().
*/
if (file_existed && S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
DEBUG(10, ("FIFO busy\n"));
smb_panic("validate_oplock_types failed");
}
- if (delay_for_oplock(fsp, 0, lease, lck, false,
- create_disposition, first_open_attempt)) {
+ delay = delay_for_oplock(fsp, 0, lease, lck, false,
+ create_disposition,
+ first_open_attempt);
+ if (delay) {
schedule_defer_open(lck, fsp->file_id, request_time,
req);
TALLOC_FREE(lck);
file_existed = true;
}
- if ((req != NULL) &&
- delay_for_oplock(
- fsp, oplock_request, lease, lck,
- NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION),
- create_disposition, first_open_attempt)) {
- schedule_defer_open(lck, fsp->file_id, request_time, req);
- TALLOC_FREE(lck);
- fd_close(fsp);
- return NT_STATUS_SHARING_VIOLATION;
+ if (req != NULL) {
+ /*
+ * Handle oplocks, deferring the request if delay_for_oplock()
+ * triggered a break message and we have to wait for the break
+ * response.
+ */
+ bool delay;
+ bool sharing_violation = NT_STATUS_EQUAL(
+ status, NT_STATUS_SHARING_VIOLATION);
+
+ delay = delay_for_oplock(fsp, oplock_request, lease, lck,
+ sharing_violation,
+ create_disposition,
+ first_open_attempt);
+ if (delay) {
+ schedule_defer_open(lck, fsp->file_id,
+ request_time, req);
+ TALLOC_FREE(lck);
+ fd_close(fsp);
+ return NT_STATUS_SHARING_VIOLATION;
+ }
}
if (!NT_STATUS_IS_OK(status)) {
- uint32 can_access_mask;
+ uint32_t can_access_mask;
bool can_access = True;
SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
/* Delete streams if create_disposition requires it */
if (!new_file_created && clear_ads(create_disposition) &&
!is_ntfs_stream_smb_fname(smb_fname)) {
- status = delete_all_streams(conn, smb_fname->base_name);
+ status = delete_all_streams(conn, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(lck);
fd_close(fsp);
if (fsp->fh->fd != -1 && lp_kernel_share_modes(SNUM(conn))) {
int ret_flock;
+ /*
+ * Beware: streams implementing VFS modules may
+ * implement streams in a way that fsp will have the
+ * basefile open in the fsp fd, so lacking a distinct
+ * fd for the stream kernel_flock will apply on the
+ * basefile which is wrong. The actual check is
+ * deffered to the VFS module implementing the
+ * kernel_flock call.
+ */
ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access, access_mask);
if(ret_flock == -1 ){
return NT_STATUS_SHARING_VIOLATION;
}
+
+ fsp->kernel_share_modes_taken = true;
}
/*
}
if (info != FILE_WAS_OPENED) {
- /* Files should be initially set as archive */
- if (lp_map_archive(SNUM(conn)) ||
+ /* Overwritten files should be initially set as archive */
+ if ((info == FILE_WAS_OVERWRITTEN && lp_map_archive(SNUM(conn))) ||
lp_store_dos_attributes(SNUM(conn))) {
if (!posix_open) {
if (file_set_dosmode(conn, smb_fname,
static NTSTATUS mkdir_internal(connection_struct *conn,
struct smb_filename *smb_dname,
- uint32 file_attributes)
+ uint32_t file_attributes)
{
mode_t mode;
char *parent_dir = NULL;
return status;
}
- if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) {
+ if (SMB_VFS_MKDIR(conn, smb_dname, mode) != 0) {
return map_nt_error_from_unix(errno);
}
*/
if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) &&
(mode & ~smb_dname->st.st_ex_mode)) {
- SMB_VFS_CHMOD(conn, smb_dname->base_name,
+ SMB_VFS_CHMOD(conn, smb_dname,
(smb_dname->st.st_ex_mode |
(mode & ~smb_dname->st.st_ex_mode)));
need_re_stat = true;
}
/* Change the owner if required. */
- if (lp_inherit_owner(SNUM(conn))) {
+ if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) {
change_dir_owner_to_parent(conn, parent_dir,
smb_dname->base_name,
&smb_dname->st);
static NTSTATUS open_directory(connection_struct *conn,
struct smb_request *req,
struct smb_filename *smb_dname,
- uint32 access_mask,
- uint32 share_access,
- uint32 create_disposition,
- uint32 create_options,
- uint32 file_attributes,
+ uint32_t access_mask,
+ uint32_t share_access,
+ uint32_t create_disposition,
+ uint32_t create_options,
+ uint32_t file_attributes,
int *pinfo,
files_struct **result)
{
nt_errstr(status)));
return status;
}
+
+ /*
+ * If mkdir_internal() returned
+ * NT_STATUS_OBJECT_NAME_COLLISION
+ * we still must lstat the path.
+ */
+
+ if (SMB_VFS_LSTAT(conn, smb_dname)
+ == -1) {
+ DEBUG(2, ("Could not stat "
+ "directory '%s' just "
+ "opened: %s\n",
+ smb_fname_str_dbg(
+ smb_dname),
+ strerror(errno)));
+ return map_nt_error_from_unix(
+ errno);
+ }
+
info = FILE_WAS_OPENED;
}
}
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
fsp->is_directory = True;
- fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
+ if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+ fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
+ }
status = fsp_set_smb_fname(fsp, smb_dname);
if (!NT_STATUS_IS_OK(status)) {
file_free(req, fsp);
return status;
}
- /* Ensure there was no race condition. */
- if (!check_same_stat(&smb_dname->st, &fsp->fsp_name->st)) {
+ if(!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+ DEBUG(5,("open_directory: %s is not a directory !\n",
+ smb_fname_str_dbg(smb_dname)));
+ fd_close(fsp);
+ file_free(req, fsp);
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+
+ /* Ensure there was no race condition. We need to check
+ * dev/inode but not permissions, as these can change
+ * legitimately */
+ if (!check_same_dev_ino(&smb_dname->st, &fsp->fsp_name->st)) {
DEBUG(5,("open_directory: stat struct differs for "
"directory %s.\n",
smb_fname_str_dbg(smb_dname)));
stream_name = NULL;
}
- smb_fname = synthetic_smb_fname(talloc_tos(), base_name,
- stream_name, NULL);
+ smb_fname = synthetic_smb_fname(talloc_tos(),
+ base_name,
+ stream_name,
+ NULL,
+ 0);
if (smb_fname == NULL) {
return;
}
* If that works, delete them all by setting the delete on close and close.
*/
-NTSTATUS open_streams_for_delete(connection_struct *conn,
- const char *fname)
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+ const struct smb_filename *smb_fname)
{
struct stream_struct *stream_info = NULL;
files_struct **streams = NULL;
TALLOC_CTX *frame = talloc_stackframe();
NTSTATUS status;
- status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+ status = vfs_streaminfo(conn, NULL, smb_fname, talloc_tos(),
&num_streams, &stream_info);
if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
}
for (i=0; i<num_streams; i++) {
- struct smb_filename *smb_fname;
+ struct smb_filename *smb_fname_cp;
if (strequal(stream_info[i].name, "::$DATA")) {
streams[i] = NULL;
continue;
}
- smb_fname = synthetic_smb_fname(
- talloc_tos(), fname, stream_info[i].name, NULL);
- if (smb_fname == NULL) {
+ smb_fname_cp = synthetic_smb_fname(talloc_tos(),
+ smb_fname->base_name,
+ stream_info[i].name,
+ NULL,
+ (smb_fname->flags &
+ ~SMB_FILENAME_POSIX_PATH));
+ if (smb_fname_cp == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
}
- if (SMB_VFS_STAT(conn, smb_fname) == -1) {
+ if (SMB_VFS_STAT(conn, smb_fname_cp) == -1) {
DEBUG(10, ("Unable to stat stream: %s\n",
- smb_fname_str_dbg(smb_fname)));
+ smb_fname_str_dbg(smb_fname_cp)));
}
status = SMB_VFS_CREATE_FILE(
conn, /* conn */
NULL, /* req */
0, /* root_dir_fid */
- smb_fname, /* fname */
+ smb_fname_cp, /* fname */
DELETE_ACCESS, /* access_mask */
(FILE_SHARE_READ | /* share_access */
FILE_SHARE_WRITE | FILE_SHARE_DELETE),
if (!NT_STATUS_IS_OK(status)) {
DEBUG(10, ("Could not open stream %s: %s\n",
- smb_fname_str_dbg(smb_fname),
+ smb_fname_str_dbg(smb_fname_cp),
nt_errstr(status)));
- TALLOC_FREE(smb_fname);
+ TALLOC_FREE(smb_fname_cp);
break;
}
- TALLOC_FREE(smb_fname);
+ TALLOC_FREE(smb_fname_cp);
}
/*
const struct dom_sid *group_sid = NULL;
uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
struct security_token *token = fsp->conn->session_info->security_token;
- bool inherit_owner = lp_inherit_owner(SNUM(fsp->conn));
+ bool inherit_owner =
+ (lp_inherit_owner(SNUM(fsp->conn)) == INHERIT_OWNER_WINDOWS_AND_UNIX);
bool inheritable_components = false;
bool try_builtin_administrators = false;
const struct dom_sid *BA_U_sid = NULL;
const struct dom_sid *SY_U_sid = NULL;
const struct dom_sid *SY_G_sid = NULL;
size_t size = 0;
+ struct smb_filename *parent_smb_fname = NULL;
if (!parent_dirname(frame, fsp->fsp_name->base_name, &parent_name, NULL)) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
+ parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+ parent_name,
+ NULL,
+ NULL,
+ fsp->fsp_name->flags);
+
+ if (parent_smb_fname == NULL) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
status = SMB_VFS_GET_NT_ACL(fsp->conn,
- parent_name,
+ parent_smb_fname,
(SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
frame,
&parent_desc);
* We can't open a file with DELETE access if any of the
* streams is open without FILE_SHARE_DELETE
*/
- status = open_streams_for_delete(conn, smb_fname->base_name);
+ status = open_streams_for_delete(conn, smb_fname);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
&& is_ntfs_stream_smb_fname(smb_fname)
&& (!(private_flags & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
- uint32 base_create_disposition;
+ uint32_t base_create_disposition;
struct smb_filename *smb_fname_base = NULL;
if (create_options & FILE_DIRECTORY_FILE) {
/* Create an smb_filename with stream_name == NULL. */
smb_fname_base = synthetic_smb_fname(talloc_tos(),
- smb_fname->base_name,
- NULL, NULL);
+ smb_fname->base_name,
+ NULL,
+ NULL,
+ smb_fname->flags);
if (smb_fname_base == NULL) {
status = NT_STATUS_NO_MEMORY;
goto fail;
/* Save the requested allocation size. */
if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
- if (allocation_size
- && (allocation_size > fsp->fsp_name->st.st_ex_size)) {
+ if ((allocation_size > fsp->fsp_name->st.st_ex_size)
+ && !(fsp->is_directory))
+ {
fsp->initial_allocation_size = smb_roundup(
fsp->conn, allocation_size);
- if (fsp->is_directory) {
- /* Can't set allocation size on a directory. */
- status = NT_STATUS_ACCESS_DENIED;
- goto fail;
- }
if (vfs_allocate_file_space(
fsp, fsp->initial_allocation_size) == -1) {
status = NT_STATUS_DISK_FULL;
files_struct *dir_fsp;
char *parent_fname = NULL;
char *new_base_name = NULL;
+ uint32_t ucf_flags = ((req != NULL && req->posix_pathnames) ?
+ UCF_POSIX_PATHNAMES : 0);
NTSTATUS status;
if (root_dir_fid == 0 || !smb_fname) {
conn,
req->flags2 & FLAGS2_DFS_PATHNAMES,
new_base_name,
- 0,
+ ucf_flags,
NULL,
smb_fname_out);
if (!NT_STATUS_IS_OK(status)) {
status = NT_STATUS_NOT_A_DIRECTORY;
goto fail;
}
- if (lp_posix_pathnames()) {
+ if (req != NULL && req->posix_pathnames) {
ret = SMB_VFS_LSTAT(conn, smb_fname);
} else {
ret = SMB_VFS_STAT(conn, smb_fname);