summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/lib/dummysmbd.c16
-rw-r--r--source3/locking/locking.c40
-rw-r--r--source3/smbd/dir.c13
-rw-r--r--source3/smbd/nttrans.c23
-rw-r--r--source3/smbd/open.c10
-rw-r--r--source3/smbd/posix_acls.c5
-rw-r--r--source3/smbd/reply.c11
-rw-r--r--source3/smbd/trans2.c14
8 files changed, 111 insertions, 21 deletions
diff --git a/source3/lib/dummysmbd.c b/source3/lib/dummysmbd.c
index 5bb71e120e..442a612f93 100644
--- a/source3/lib/dummysmbd.c
+++ b/source3/lib/dummysmbd.c
@@ -37,3 +37,19 @@ BOOL conn_snum_used(int snum)
void cancel_pending_lock_requests_by_fid(files_struct *fsp, struct byte_range_lock *br_lck)
{
}
+
+NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
+ const char *wcard, BOOL wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
+{
+ return NT_STATUS_OK;
+}
+
+int dptr_CloseDir(struct dptr_struct *dptr)
+{
+ return 0;
+}
+
+const char *dptr_ReadDirName(struct dptr_struct *dptr, long *poffset, SMB_STRUCT_STAT *pst)
+{
+ return NULL;
+}
diff --git a/source3/locking/locking.c b/source3/locking/locking.c
index 13c7724656..111fc98bbe 100644
--- a/source3/locking/locking.c
+++ b/source3/locking/locking.c
@@ -1152,6 +1152,46 @@ NTSTATUS can_set_delete_on_close(files_struct *fsp, BOOL delete_on_close,
return NT_STATUS_ACCESS_DENIED;
}
+ /* Don't allow delete on close for non-empty directories. */
+ if (fsp->is_directory) {
+ long offset = 0;
+ NTSTATUS status;
+ SMB_STRUCT_STAT st;
+ struct dptr_struct *dirptr;
+ const char *name;
+
+ status = dptr_create(fsp->conn,
+ fsp->fsp_name,
+ False,
+ True,
+ 0,
+ "*",
+ True,
+ 0,
+ &dirptr);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
+
+ /* Read 3 entries. Ignore first 2 (they're . and .. ) */
+ name = dptr_ReadDirName(dirptr, &offset, &st);
+ if (!name) {
+ dptr_CloseDir(dirptr);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ name = dptr_ReadDirName(dirptr, &offset, &st);
+ if (!name) {
+ dptr_CloseDir(dirptr);
+ return NT_STATUS_ACCESS_DENIED;
+ }
+ name = dptr_ReadDirName(dirptr, &offset, &st);
+ dptr_CloseDir(dirptr);
+ if (name) {
+ DEBUG(10,("can_set_delete_on_close: got name %s - can't delete\n", name ));
+ return NT_STATUS_DIRECTORY_NOT_EMPTY;
+ }
+ }
+
return NT_STATUS_OK;
}
diff --git a/source3/smbd/dir.c b/source3/smbd/dir.c
index 7be5c03f1b..98356882aa 100644
--- a/source3/smbd/dir.c
+++ b/source3/smbd/dir.c
@@ -383,7 +383,7 @@ static void dptr_close_oldest(BOOL old)
****************************************************************************/
NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOOL expect_close,uint16 spid,
- const char *wcard, BOOL wcard_has_wild, uint32 attr, int *dptr_hnd_ret)
+ const char *wcard, BOOL wcard_has_wild, uint32 attr, struct dptr_struct **dptr_ret)
{
struct dptr_struct *dptr = NULL;
struct smb_Dir *dir_hnd;
@@ -392,8 +392,6 @@ NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOO
DEBUG(5,("dptr_create dir=%s\n", path));
- *dptr_hnd_ret = -1;
-
if (!wcard) {
return NT_STATUS_INVALID_PARAMETER;
}
@@ -517,9 +515,8 @@ NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOO
DEBUG(3,("creating new dirptr %d for path %s, expect_close = %d\n",
dptr->dnum,path,expect_close));
- conn->dirptr = dptr;
+ *dptr_ret = dptr;
- *dptr_hnd_ret = dptr->dnum;
return NT_STATUS_OK;
}
@@ -530,6 +527,7 @@ NTSTATUS dptr_create(connection_struct *conn, pstring path, BOOL old_handle, BOO
int dptr_CloseDir(struct dptr_struct *dptr)
{
+ DLIST_REMOVE(dirptrs, dptr);
return CloseDir(dptr->dir_hnd);
}
@@ -548,6 +546,11 @@ BOOL dptr_has_wild(struct dptr_struct *dptr)
return dptr->has_wild;
}
+int dptr_dnum(struct dptr_struct *dptr)
+{
+ return dptr->dnum;
+}
+
/****************************************************************************
Return the next visible file name, skipping veto'd and invisible files.
****************************************************************************/
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index ac7beabb53..51a4093f29 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -652,11 +652,13 @@ int reply_ntcreate_and_X(connection_struct *conn,
if (lp_acl_check_permissions(SNUM(conn))
&& (create_disposition != FILE_CREATE)
&& (share_access & FILE_SHARE_DELETE)
- && (access_mask & DELETE_ACCESS)
- && !can_delete_file_in_directory(conn, fname)) {
- restore_case_semantics(conn, file_attributes);
- END_PROFILE(SMBntcreateX);
- return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ && (access_mask & DELETE_ACCESS)) {
+ if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) ||
+ !can_delete_file_in_directory(conn, fname)) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
}
/*
@@ -1277,10 +1279,13 @@ static int call_nt_transact_create(connection_struct *conn, char *inbuf, char *o
if (lp_acl_check_permissions(SNUM(conn))
&& (create_disposition != FILE_CREATE)
&& (share_access & FILE_SHARE_DELETE)
- && (access_mask & DELETE_ACCESS)
- && !can_delete_file_in_directory(conn, fname)) {
- restore_case_semantics(conn, file_attributes);
- return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ && (access_mask & DELETE_ACCESS)) {
+ if ((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY) ||
+ !can_delete_file_in_directory(conn, fname)) {
+ restore_case_semantics(conn, file_attributes);
+ END_PROFILE(SMBntcreateX);
+ return ERROR_NT(NT_STATUS_ACCESS_DENIED);
+ }
}
if (ea_len) {
diff --git a/source3/smbd/open.c b/source3/smbd/open.c
index 4249c6e85b..c0638c0039 100644
--- a/source3/smbd/open.c
+++ b/source3/smbd/open.c
@@ -2110,15 +2110,17 @@ NTSTATUS open_directory(connection_struct *conn,
always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
if (create_options & FILE_DELETE_ON_CLOSE) {
status = can_set_delete_on_close(fsp, True, 0);
- if (!NT_STATUS_IS_OK(status)) {
+ if (!NT_STATUS_IS_OK(status) && !NT_STATUS_EQUAL(status, NT_STATUS_DIRECTORY_NOT_EMPTY)) {
TALLOC_FREE(lck);
file_free(fsp);
return status;
}
- set_delete_on_close_token(lck, &current_user.ut);
- lck->initial_delete_on_close = True;
- lck->modified = True;
+ if (NT_STATUS_IS_OK(status)) {
+ set_delete_on_close_token(lck, &current_user.ut);
+ lck->initial_delete_on_close = True;
+ lck->modified = True;
+ }
}
TALLOC_FREE(lck);
diff --git a/source3/smbd/posix_acls.c b/source3/smbd/posix_acls.c
index c5da33c9df..630e270de3 100644
--- a/source3/smbd/posix_acls.c
+++ b/source3/smbd/posix_acls.c
@@ -4221,6 +4221,11 @@ BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
if (sbuf.st_mode & S_ISVTX) {
SMB_STRUCT_STAT sbuf_file;
if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
+ if (errno == ENOENT) {
+ /* If the file doesn't already exist then
+ * yes we'll be able to delete it. */
+ return True;
+ }
return False;
}
/*
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 4d139be98f..2075939f5b 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -1013,10 +1013,19 @@ int reply_search(connection_struct *conn, char *inbuf,char *outbuf, int dum_size
p = smb_buf(outbuf) + 3;
if (status_len == 0) {
- nt_status = dptr_create(conn,directory,True,expect_close,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype,&dptr_num);
+ nt_status = dptr_create(conn,
+ directory,
+ True,
+ expect_close,
+ SVAL(inbuf,smb_pid),
+ mask,
+ mask_contains_wcard,
+ dirtype,
+ &conn->dirptr);
if (!NT_STATUS_IS_OK(nt_status)) {
return ERROR_NT(nt_status);
}
+ dptr_num = dptr_dnum(conn->dirptr);
} else {
dirtype = dptr_attr(dptr_num);
}
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index e91a2134fd..c9cb2c5b4f 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -1794,13 +1794,23 @@ total_data=%u (should be %u)\n", (unsigned int)total_data, (unsigned int)IVAL(pd
/* Save the wildcard match and attribs we are using on this directory -
needed as lanman2 assumes these are being saved between calls */
- ntstatus = dptr_create(conn,directory, False, True ,SVAL(inbuf,smb_pid), mask, mask_contains_wcard, dirtype, &dptr_num);
+ ntstatus = dptr_create(conn,
+ directory,
+ False,
+ True,
+ SVAL(inbuf,smb_pid),
+ mask,
+ mask_contains_wcard,
+ dirtype,
+ &conn->dirptr);
+
if (!NT_STATUS_IS_OK(ntstatus)) {
talloc_destroy(ea_ctx);
return ERROR_NT(ntstatus);
}
- DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n",dptr_num, mask, dirtype));
+ dptr_num = dptr_dnum(conn->dirptr);
+ DEBUG(4,("dptr_num is %d, wcard = %s, attr = %d\n", dptr_num, mask, dirtype));
/* We don't need to check for VOL here as this is returned by
a different TRANS2 call. */