uint32_t access_mask)
{
NTSTATUS status;
- char *parent_dir = NULL;
struct security_descriptor *parent_sd = NULL;
uint32_t access_granted = 0;
- struct smb_filename *parent_smb_fname = NULL;
+ struct smb_filename *parent_dir = NULL;
struct share_mode_lock *lck = NULL;
struct file_id id = {0};
uint32_t name_hash;
bool delete_on_close_set;
int ret;
TALLOC_CTX *frame = talloc_stackframe();
+ bool ok;
- if (!parent_dirname(frame,
- smb_fname->base_name,
- &parent_dir,
- NULL)) {
- status = NT_STATUS_NO_MEMORY;
- goto out;
- }
-
- parent_smb_fname = synthetic_smb_fname(frame,
- parent_dir,
- NULL,
- NULL,
- smb_fname->flags);
- if (parent_smb_fname == NULL) {
+ ok = parent_smb_fname(frame, smb_fname, &parent_dir, NULL);
+ if (!ok) {
status = NT_STATUS_NO_MEMORY;
goto out;
}
}
status = SMB_VFS_GET_NT_ACL(conn,
- parent_smb_fname,
+ parent_dir,
SECINFO_DACL,
frame,
&parent_sd);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5,("check_parent_access: SMB_VFS_GET_NT_ACL failed for "
"%s with error %s\n",
- parent_dir,
+ smb_fname_str_dbg(parent_dir),
nt_errstr(status)));
goto out;
}
DEBUG(5,("check_parent_access: access check "
"on directory %s for "
"path %s for mask 0x%x returned (0x%x) %s\n",
- parent_dir,
+ smb_fname_str_dbg(parent_dir),
smb_fname->base_name,
access_mask,
access_granted,
}
/* Check if the directory has delete-on-close set */
- ret = SMB_VFS_STAT(conn, parent_smb_fname);
+ ret = SMB_VFS_STAT(conn, parent_dir);
if (ret != 0) {
status = map_nt_error_from_unix(errno);
goto out;
}
- id = SMB_VFS_FILE_ID_CREATE(conn, &parent_smb_fname->st);
+ id = SMB_VFS_FILE_ID_CREATE(conn, &parent_dir->st);
- status = file_name_hash(conn, parent_smb_fname->base_name, &name_hash);
+ status = file_name_hash(conn, parent_dir->base_name, &name_hash);
if (!NT_STATUS_IS_OK(status)) {
goto out;
}
struct smb_filename *smb_fname_rel = NULL;
int saved_errno = 0;
struct smb_filename *oldwd_fname = NULL;
- char *parent_dir = NULL;
- struct smb_filename parent_dir_fname = {0};
- const char *final_component = NULL;
- bool is_directory = false;
+ struct smb_filename *parent_dir_fname = NULL;
bool ok;
-#ifdef O_DIRECTORY
- if (flags & O_DIRECTORY) {
- is_directory = true;
- }
-#endif
-
- if (is_directory) {
- parent_dir = talloc_strdup(talloc_tos(), smb_fname->base_name);
- if (parent_dir == NULL) {
+ if (fsp->fsp_flags.is_directory) {
+ parent_dir_fname = cp_smb_filename(talloc_tos(), smb_fname);
+ if (parent_dir_fname == NULL) {
saved_errno = errno;
goto out;
}
- final_component = ".";
+ smb_fname_rel = synthetic_smb_fname(parent_dir_fname,
+ ".",
+ smb_fname->stream_name,
+ &smb_fname->st,
+ smb_fname->flags);
+ if (smb_fname_rel == NULL) {
+ saved_errno = errno;
+ goto out;
+ }
} else {
- ok = parent_dirname(talloc_tos(),
- smb_fname->base_name,
- &parent_dir,
- &final_component);
+ ok = parent_smb_fname(talloc_tos(),
+ smb_fname,
+ &parent_dir_fname,
+ &smb_fname_rel);
if (!ok) {
saved_errno = errno;
goto out;
}
}
- parent_dir_fname = (struct smb_filename) { .base_name = parent_dir };
-
oldwd_fname = vfs_GetWd(talloc_tos(), conn);
if (oldwd_fname == NULL) {
goto out;
}
/* Pin parent directory in place. */
- if (vfs_ChDir(conn, &parent_dir_fname) == -1) {
- goto out;
- }
-
- smb_fname_rel = synthetic_smb_fname(talloc_tos(),
- final_component,
- smb_fname->stream_name,
- &smb_fname->st,
- smb_fname->flags);
- if (smb_fname_rel == NULL) {
- saved_errno = ENOMEM;
+ if (vfs_ChDir(conn, parent_dir_fname) == -1) {
goto out;
}
/* Ensure the relative path is below the share. */
- status = check_reduced_name(conn, &parent_dir_fname, smb_fname_rel);
+ status = check_reduced_name(conn, parent_dir_fname, smb_fname_rel);
if (!NT_STATUS_IS_OK(status)) {
saved_errno = map_errno_from_nt_status(status);
goto out;
out:
- TALLOC_FREE(parent_dir);
- TALLOC_FREE(smb_fname_rel);
+ TALLOC_FREE(parent_dir_fname);
if (oldwd_fname != NULL) {
int ret = vfs_ChDir(conn, oldwd_fname);
{
struct smb_filename *smb_fname = fsp->fsp_name;
NTSTATUS status = NT_STATUS_OK;
+ struct smb_filename *conn_rootdir_fname = NULL;
+ const char *conn_rootdir;
+ int saved_errno = 0;
/*
* Never follow symlinks on a POSIX client. The
}
/* 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);
- int saved_errno = 0;
+ conn_rootdir = SMB_VFS_CONNECTPATH(conn,
+ smb_fname);
- 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_fname,
- fsp,
- smb_fname,
- flags,
- mode,
+ if (conn_rootdir == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ conn_rootdir_fname = synthetic_smb_fname(talloc_tos(),
+ conn_rootdir,
+ NULL,
+ NULL,
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);
+ 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_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;
}
if (fsp->fh->fd == -1) {
static NTSTATUS open_file(files_struct *fsp,
connection_struct *conn,
struct smb_request *req,
- const char *parent_dir,
+ struct smb_filename *parent_dir,
int flags,
mode_t unx_mode,
uint32_t access_mask, /* client requested access mask. */
int accmode = (flags & O_ACCMODE);
int local_flags = flags;
bool file_existed = VALID_STAT(fsp->fsp_name->st);
+ uint32_t need_fd_mask =
+ FILE_READ_DATA |
+ FILE_WRITE_DATA |
+ FILE_APPEND_DATA |
+ FILE_EXECUTE |
+ WRITE_DAC_ACCESS |
+ WRITE_OWNER_ACCESS |
+ SEC_FLAG_SYSTEM_SECURITY |
+ READ_CONTROL_ACCESS;
+ bool creating = !file_existed && (flags & O_CREAT);
+ bool truncating = (flags & O_TRUNC);
fsp->fh->fd = -1;
errno = EPERM;
local_flags = (flags & ~O_ACCMODE)|O_RDWR;
}
- if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|
- FILE_APPEND_DATA|FILE_EXECUTE|
- WRITE_DAC_ACCESS|WRITE_OWNER_ACCESS|
- READ_CONTROL_ACCESS))||
- (!file_existed && (local_flags & O_CREAT)) ||
- ((local_flags & O_TRUNC) == O_TRUNC) ) {
+ if ((open_access_mask & need_fd_mask) || creating || truncating) {
const char *wild;
int ret;
if (file_existed && S_ISFIFO(smb_fname->st.st_ex_mode)) {
local_flags &= ~O_TRUNC; /* Can't truncate a FIFO. */
local_flags |= O_NONBLOCK;
+ truncating = false;
}
#endif
/* Inherit the ACL if required */
if (lp_inherit_permissions(SNUM(conn))) {
- inherit_access_posix_acl(conn, parent_dir,
+ inherit_access_posix_acl(conn,
+ parent_dir->base_name,
smb_fname,
unx_mode);
need_re_stat = true;
/* Change the owner if required. */
if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) {
- change_file_owner_to_parent(conn, parent_dir,
+ change_file_owner_to_parent(conn,
+ parent_dir->base_name,
fsp);
need_re_stat = true;
}
fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
fsp->file_pid = req ? req->smbpid : 0;
- fsp->can_lock = True;
- fsp->can_read = ((access_mask & FILE_READ_DATA) != 0);
- fsp->can_write =
+ fsp->fsp_flags.can_lock = true;
+ fsp->fsp_flags.can_read = ((access_mask & FILE_READ_DATA) != 0);
+ fsp->fsp_flags.can_write =
CAN_WRITE(conn) &&
((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) != 0);
fsp->print_file = NULL;
- fsp->modified = False;
+ fsp->fsp_flags.modified = false;
fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->is_directory = False;
+ fsp->fsp_flags.is_directory = false;
if (conn->aio_write_behind_list &&
is_in_path(smb_fname->base_name, conn->aio_write_behind_list,
conn->case_sensitive)) {
- fsp->aio_write_behind = True;
+ fsp->fsp_flags.aio_write_behind = true;
}
- fsp->wcp = NULL; /* Write cache pointer. */
-
DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
conn->session_info->unix_info->unix_name,
smb_fname_str_dbg(smb_fname),
- BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
+ BOOLSTR(fsp->fsp_flags.can_read),
+ BOOLSTR(fsp->fsp_flags.can_write),
conn->num_files_open));
errno = 0;
struct validate_my_share_entries_state *state = private_data;
files_struct *fsp;
- if (!serverid_equal(&state->self, &e->pid)) {
+ if (!server_id_equal(&state->self, &e->pid)) {
return false;
}
struct share_mode_data *d = lck->data;
struct open_mode_check_state state;
uint16_t new_flags;
- bool ok, conflict;
+ bool ok, conflict, have_share_entries;
if (is_stat_open(access_mask)) {
/* Stat open that doesn't trigger oplock breaks or share mode
}
#endif
- if (d->num_share_modes == 0) {
+ have_share_entries = share_mode_have_entries(lck);
+ if (!have_share_entries) {
+ /*
+ * This is a fresh share mode lock where no conflicts
+ * can happen.
+ */
return NT_STATUS_OK;
}
}
}
- if (granted & SMB2_LEASE_READ) {
+ if ((granted & SMB2_LEASE_READ) &&
+ ((lck->data->flags & SHARE_MODE_LEASE_READ) == 0)) {
lck->data->flags |= SHARE_MODE_LEASE_READ;
+ lck->data->modified = true;
}
DBG_DEBUG("oplock type 0x%x on file %s\n",
static void defer_open(struct share_mode_lock *lck,
struct timeval timeout,
struct smb_request *req,
- bool delayed_for_oplocks,
struct file_id id)
{
struct deferred_open_record *open_rec = NULL;
abs_timeout = timeval_sum(&req->request_time, &timeout);
DBG_DEBUG("request time [%s] timeout [%s] mid [%" PRIu64 "] "
- "delayed_for_oplocks [%s] file_id [%s]\n",
+ "file_id [%s]\n",
timeval_str_buf(&req->request_time, false, true, &tvbuf1),
timeval_str_buf(&abs_timeout, false, true, &tvbuf2),
req->mid,
- delayed_for_oplocks ? "yes" : "no",
file_id_str_buf(id, &fbuf));
open_rec = talloc_zero(NULL, struct deferred_open_record);
DBG_DEBUG("defering mid %" PRIu64 "\n", req->mid);
- watch_req = dbwrap_watched_watch_send(watch_state,
- req->sconn->ev_ctx,
- lck->data->record,
- (struct server_id){0});
+ watch_req = share_mode_watch_send(
+ watch_state,
+ req->sconn->ev_ctx,
+ lck->data->id,
+ (struct server_id){0});
if (watch_req == NULL) {
exit_server("Could not watch share mode record");
}
NTSTATUS status;
bool ret;
- status = dbwrap_watched_watch_recv(req, NULL, NULL);
+ status = share_mode_watch_recv(req, NULL, NULL);
TALLOC_FREE(req);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(5, ("dbwrap_watched_watch_recv returned %s\n",
}
if (lck != NULL) {
- open_rec->watch_req = dbwrap_watched_watch_send(
+ open_rec->watch_req = share_mode_watch_send(
open_rec,
req->sconn->ev_ctx,
- lck->data->record,
+ lck->data->id,
(struct server_id) {0});
if (open_rec->watch_req == NULL) {
- DBG_WARNING("dbwrap_watched_watch_send failed\n");
+ DBG_WARNING("share_mode_watch_send failed\n");
TALLOC_FREE(open_rec);
return false;
}
NTSTATUS status;
bool ok;
- status = dbwrap_watched_watch_recv(subreq, NULL, NULL);
+ status = share_mode_watch_recv(subreq, NULL, NULL);
TALLOC_FREE(subreq);
DBG_DEBUG("dbwrap_watched_watch_recv returned %s\n",
nt_errstr(status));
return;
}
- defer_open(lck, timeout, req, true, id);
+ defer_open(lck, timeout, req, id);
}
/****************************************************************************
struct share_mode_lock *lck = NULL;
uint32_t open_access_mask = access_mask;
NTSTATUS status;
- char *parent_dir;
+ struct smb_filename *parent_dir_fname = NULL;
SMB_STRUCT_STAT saved_stat = smb_fname->st;
struct timespec old_write_time;
struct file_id id;
+ bool setup_poll = false;
bool ok;
if (conn->printer) {
req->vuid);
}
- if (!parent_dirname(talloc_tos(), smb_fname->base_name, &parent_dir,
- NULL)) {
+ ok = parent_smb_fname(talloc_tos(),
+ smb_fname,
+ &parent_dir_fname,
+ NULL);
+ if (!ok) {
return NT_STATUS_NO_MEMORY;
}
/* We add FILE_ATTRIBUTE_ARCHIVE to this as this mode is only used if the file is
* created new. */
unx_mode = unix_mode(conn, new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE,
- smb_fname, parent_dir);
+ smb_fname, parent_dir_fname);
}
DEBUG(10, ("open_file_ntcreate: fname=%s, dos_attrs=0x%x "
return NT_STATUS_ACCESS_DENIED;
}
- fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
+ if (VALID_STAT(smb_fname->st)) {
+ /*
+ * Only try and create a file id before open
+ * for an existing file. For a file being created
+ * this won't do anything useful until the file
+ * exists and has a valid stat struct.
+ */
+ fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
+ }
fsp->fh->private_options = private_flags;
fsp->access_mask = open_access_mask; /* We change this to the
* requested access_mask after
*/
if ((flags2 & O_CREAT) && lp_inherit_acls(SNUM(conn)) &&
- (def_acl = directory_has_default_acl(conn, parent_dir))) {
+ (def_acl = directory_has_default_acl(conn, parent_dir_fname))) {
unx_mode = (0777 & lp_create_mask(SNUM(conn)));
}
(unsigned int)unx_mode, (unsigned int)access_mask,
(unsigned int)open_access_mask));
- fsp_open = open_file(fsp, conn, req, parent_dir,
+ fsp_open = open_file(fsp, conn, req, parent_dir_fname,
flags|flags2, unx_mode, access_mask,
open_access_mask, &new_file_created);
if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_NETWORK_BUSY)) {
+ if (file_existed && S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
+ DEBUG(10, ("FIFO busy\n"));
+ return NT_STATUS_NETWORK_BUSY;
+ }
+ if (req == NULL) {
+ DEBUG(10, ("Internal open busy\n"));
+ return NT_STATUS_NETWORK_BUSY;
+ }
/*
* This handles the kernel oplock case:
*
* "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"));
- return NT_STATUS_NETWORK_BUSY;
- }
- if (req == NULL) {
- DEBUG(10, ("Internal open busy\n"));
- return NT_STATUS_NETWORK_BUSY;
- }
+ setup_poll = true;
+ }
+ if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_RETRY)) {
+ /*
+ * EINTR from the open(2) syscall. Just setup a retry
+ * in a bit. We can't use the sys_write() tight retry
+ * loop here, as we might have to actually deal with
+ * lease-break signals to avoid a deadlock.
+ */
+ setup_poll = true;
+ }
+
+ if (setup_poll) {
/*
* From here on we assume this is an oplock break triggered
*/
}
if (!NT_STATUS_IS_OK(fsp_open)) {
- if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_RETRY)) {
+ bool wait_for_aio = NT_STATUS_EQUAL(
+ fsp_open, NT_STATUS_MORE_PROCESSING_REQUIRED);
+ if (wait_for_aio) {
schedule_async_open(req);
}
return fsp_open;
return NT_STATUS_SHARING_VIOLATION;
}
- fsp->kernel_share_modes_taken = true;
+ fsp->fsp_flags.kernel_share_modes_taken = true;
}
/*
}
/* Note that here we set the *initial* delete on close flag,
not the regular one. The magic gets handled in close. */
- fsp->initial_delete_on_close = True;
+ fsp->fsp_flags.initial_delete_on_close = true;
}
/*
if (!posix_open) {
if (file_set_dosmode(conn, smb_fname,
new_dos_attributes | FILE_ATTRIBUTE_ARCHIVE,
- parent_dir, true) == 0) {
+ parent_dir_fname, true) == 0) {
unx_mode = smb_fname->st.st_ex_mode;
}
}
/* Determine sparse flag. */
if (posix_open) {
/* POSIX opens are sparse by default. */
- fsp->is_sparse = true;
+ fsp->fsp_flags.is_sparse = true;
} else {
- fsp->is_sparse =
+ fsp->fsp_flags.is_sparse =
(existing_dos_attributes & FILE_ATTRIBUTE_SPARSE);
}
*/
struct timespec write_time = get_share_mode_write_time(lck);
- if (!null_timespec(write_time)) {
+ if (!is_omit_timespec(&write_time)) {
update_stat_ex_mtime(&fsp->fsp_name->st, write_time);
}
}
struct smb_filename *smb_dname,
uint32_t file_attributes)
{
+ const struct loadparm_substitution *lp_sub =
+ loadparm_s3_global_substitution();
mode_t mode;
+ struct smb_filename *parent_dir_fname = NULL;
char *parent_dir = NULL;
NTSTATUS status;
bool posix_open = false;
bool need_re_stat = false;
uint32_t access_mask = SEC_DIR_ADD_SUBDIR;
int ret;
+ bool ok;
if (!CAN_WRITE(conn) || (access_mask & ~(conn->share_access))) {
DEBUG(5,("mkdir_internal: failing share access "
- "%s\n", lp_servicename(talloc_tos(), SNUM(conn))));
+ "%s\n", lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
return NT_STATUS_ACCESS_DENIED;
}
- if (!parent_dirname(talloc_tos(), smb_dname->base_name, &parent_dir,
- NULL)) {
+ ok = parent_smb_fname(talloc_tos(),
+ smb_dname,
+ &parent_dir_fname,
+ NULL);
+ if (!ok) {
return NT_STATUS_NO_MEMORY;
}
+ parent_dir = parent_dir_fname->base_name;
if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
posix_open = true;
mode = (mode_t)(file_attributes & ~FILE_FLAG_POSIX_SEMANTICS);
} else {
- mode = unix_mode(conn, FILE_ATTRIBUTE_DIRECTORY, smb_dname, parent_dir);
+ mode = unix_mode(conn,
+ FILE_ATTRIBUTE_DIRECTORY,
+ smb_dname,
+ parent_dir_fname);
}
status = check_parent_access(conn,
if (!posix_open) {
file_set_dosmode(conn, smb_dname,
file_attributes | FILE_ATTRIBUTE_DIRECTORY,
- parent_dir, true);
+ parent_dir_fname, true);
}
}
files_struct **result)
{
files_struct *fsp = NULL;
- bool dir_existed = VALID_STAT(smb_dname->st) ? True : False;
+ bool dir_existed = VALID_STAT(smb_dname->st);
struct share_mode_lock *lck = NULL;
NTSTATUS status;
struct timespec mtimespec;
file_attributes |= FILE_ATTRIBUTE_DIRECTORY;
}
- DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
- "share_access = 0x%x create_options = 0x%x, "
- "create_disposition = 0x%x, file_attributes = 0x%x\n",
+ DBG_INFO("opening directory %s, access_mask = 0x%"PRIx32", "
+ "share_access = 0x%"PRIx32" create_options = 0x%"PRIx32", "
+ "create_disposition = 0x%"PRIx32", "
+ "file_attributes = 0x%"PRIx32"\n",
smb_fname_str_dbg(smb_dname),
- (unsigned int)access_mask,
- (unsigned int)share_access,
- (unsigned int)create_options,
- (unsigned int)create_disposition,
- (unsigned int)file_attributes));
+ access_mask,
+ share_access,
+ create_options,
+ create_disposition,
+ file_attributes);
status = smbd_calculate_access_mask(conn, smb_dname, false,
access_mask, &access_mask);
fsp->file_id = vfs_file_id_from_sbuf(conn, &smb_dname->st);
fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
fsp->file_pid = req ? req->smbpid : 0;
- fsp->can_lock = False;
- fsp->can_read = False;
- fsp->can_write = False;
+ fsp->fsp_flags.can_lock = false;
+ fsp->fsp_flags.can_read = false;
+ fsp->fsp_flags.can_write = false;
fsp->fh->private_options = 0;
/*
*/
fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
fsp->print_file = NULL;
- fsp->modified = False;
+ fsp->fsp_flags.modified = false;
fsp->oplock_type = NO_OPLOCK;
fsp->sent_oplock_break = NO_BREAK_SENT;
- fsp->is_directory = True;
+ fsp->fsp_flags.is_directory = true;
if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
}
/* Don't store old timestamps for directory
handles in the internal database. We don't
update them in there if new objects
- are creaded in the directory. Currently
+ are created in the directory. Currently
we only update timestamps on file writes.
See bug #9870.
*/
- ZERO_STRUCT(mtimespec);
+ mtimespec = make_omit_timespec();
#ifdef O_DIRECTORY
status = fd_open(conn, fsp, O_RDONLY|O_DIRECTORY, 0);
if (NT_STATUS_IS_OK(status)) {
/* Note that here we set the *initial* delete on close flag,
not the regular one. The magic gets handled in close. */
- fsp->initial_delete_on_close = True;
+ fsp->fsp_flags.initial_delete_on_close = true;
}
}
*/
struct timespec write_time = get_share_mode_write_time(lck);
- if (!null_timespec(write_time)) {
+ if (!is_omit_timespec(&write_time)) {
update_stat_ex_mtime(&fsp->fsp_name->st, write_time);
}
}
static NTSTATUS inherit_new_acl(files_struct *fsp)
{
TALLOC_CTX *frame = talloc_stackframe();
- char *parent_name = NULL;
struct security_descriptor *parent_desc = NULL;
NTSTATUS status = NT_STATUS_OK;
struct security_descriptor *psd = 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);
+ struct smb_filename *parent_dir = NULL;
+ bool ok;
- if (parent_smb_fname == NULL) {
+ ok = parent_smb_fname(frame,
+ fsp->fsp_name,
+ &parent_dir,
+ NULL);
+ if (!ok) {
TALLOC_FREE(frame);
return NT_STATUS_NO_MEMORY;
}
status = SMB_VFS_GET_NT_ACL(fsp->conn,
- parent_smb_fname,
+ parent_dir,
(SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
frame,
&parent_desc);
}
inheritable_components = sd_has_inheritable_components(parent_desc,
- fsp->is_directory);
+ fsp->fsp_flags.is_directory);
if (!inheritable_components && !inherit_owner) {
TALLOC_FREE(frame);
if (try_builtin_administrators) {
struct unixid ids;
- bool ok;
ZERO_STRUCT(ids);
ok = sids_to_unixids(&global_sid_Builtin_Administrators, 1, &ids);
if (try_system) {
struct unixid ids;
- bool ok;
ZERO_STRUCT(ids);
ok = sids_to_unixids(&global_sid_System, 1, &ids);
parent_desc,
owner_sid,
group_sid,
- fsp->is_directory);
+ fsp->fsp_flags.is_directory);
if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
return status;
}
}
- if ((access_mask & SEC_FLAG_SYSTEM_SECURITY) &&
- !security_token_has_privilege(get_current_nttok(conn),
- SEC_PRIV_SECURITY)) {
- DEBUG(10, ("create_file_unixpath: open on %s "
- "failed - SEC_FLAG_SYSTEM_SECURITY denied.\n",
- smb_fname_str_dbg(smb_fname)));
- status = NT_STATUS_PRIVILEGE_NOT_HELD;
- goto fail;
+ if (access_mask & SEC_FLAG_SYSTEM_SECURITY) {
+ bool ok;
+
+ ok = security_token_has_privilege(get_current_nttok(conn),
+ SEC_PRIV_SECURITY);
+ if (!ok) {
+ DBG_DEBUG("open on %s failed - "
+ "SEC_FLAG_SYSTEM_SECURITY denied.\n",
+ smb_fname_str_dbg(smb_fname));
+ status = NT_STATUS_PRIVILEGE_NOT_HELD;
+ goto fail;
+ }
+
+ if (conn->sconn->using_smb2 &&
+ (access_mask == SEC_FLAG_SYSTEM_SECURITY))
+ {
+ /*
+ * No other bits set. Windows SMB2 refuses this.
+ * See smbtorture3 SMB2-SACL test.
+ *
+ * Note this is an SMB2-only behavior,
+ * smbtorture3 SMB1-SYSTEM-SECURITY already tests
+ * that SMB1 allows this.
+ */
+ status = NT_STATUS_ACCESS_DENIED;
+ goto fail;
+ }
}
/*
}
}
- if (!fsp->is_directory && S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+ if (!fsp->fsp_flags.is_directory &&
+ S_ISDIR(fsp->fsp_name->st.st_ex_mode))
+ {
status = NT_STATUS_ACCESS_DENIED;
goto fail;
}
/* Save the requested allocation size. */
if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
if ((allocation_size > (uint64_t)fsp->fsp_name->st.st_ex_size)
- && !(fsp->is_directory))
+ && !(fsp->fsp_flags.is_directory))
{
fsp->initial_allocation_size = smb_roundup(
fsp->conn, allocation_size);
goto out;
}
- if (!dir_fsp->is_directory) {
+ if (!dir_fsp->fsp_flags.is_directory) {
/*
* Check to see if this is a mac fork of some kind.
files_struct *fsp = NULL;
NTSTATUS status;
bool stream_name = false;
+ struct smb2_create_blob *posx = NULL;
DBG_DEBUG("create_file: access_mask = 0x%x "
"file_attributes = 0x%x, share_access = 0x%x, "
}
}
+ posx = smb2_create_blob_find(
+ in_context_blobs, SMB2_CREATE_TAG_POSIX);
+ if (posx != NULL) {
+ uint32_t wire_mode_bits = 0;
+ mode_t mode_bits = 0;
+ SMB_STRUCT_STAT sbuf = { 0 };
+ enum perm_type ptype =
+ (create_options & FILE_DIRECTORY_FILE) ?
+ PERM_NEW_DIR : PERM_NEW_FILE;
+
+ if (posx->data.length != 4) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+
+ wire_mode_bits = IVAL(posx->data.data, 0);
+ status = unix_perms_from_wire(
+ conn, &sbuf, wire_mode_bits, ptype, &mode_bits);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto fail;
+ }
+ /*
+ * Remove type info from mode, leaving only the
+ * permissions and setuid/gid bits.
+ */
+ mode_bits &= ~S_IFMT;
+
+ file_attributes = (FILE_FLAG_POSIX_SEMANTICS | mode_bits);
+ }
+
status = create_file_unixpath(
conn, req, smb_fname, access_mask, share_access,
create_disposition, create_options, file_attributes,