summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--source3/include/proto.h3
-rw-r--r--source3/smbd/close.c260
-rw-r--r--source3/smbd/reply.c300
3 files changed, 298 insertions, 265 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index d8fa437375..6ae9e8801e 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6897,9 +6897,6 @@ void reply_printclose(struct smb_request *req);
void reply_printqueue(struct smb_request *req);
void reply_printwrite(struct smb_request *req);
void reply_mkdir(struct smb_request *req);
-NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
- connection_struct *conn,
- struct smb_filename *smb_dname);
void reply_rmdir(struct smb_request *req);
NTSTATUS rename_internals_fsp(connection_struct *conn,
files_struct *fsp,
diff --git a/source3/smbd/close.c b/source3/smbd/close.c
index afba07f1f5..05c3c709a1 100644
--- a/source3/smbd/close.c
+++ b/source3/smbd/close.c
@@ -656,6 +656,263 @@ static NTSTATUS close_normal_file(struct smb_request *req, files_struct *fsp,
file_free(req, fsp);
return status;
}
+/****************************************************************************
+ Static function used by reply_rmdir to delete an entire directory
+ tree recursively. Return True on ok, False on fail.
+****************************************************************************/
+
+static bool recursive_rmdir(TALLOC_CTX *ctx,
+ connection_struct *conn,
+ struct smb_filename *smb_dname)
+{
+ const char *dname = NULL;
+ char *talloced = NULL;
+ bool ret = True;
+ long offset = 0;
+ SMB_STRUCT_STAT st;
+ struct smb_Dir *dir_hnd;
+
+ SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
+
+ dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
+ if(dir_hnd == NULL)
+ return False;
+
+ while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
+ struct smb_filename *smb_dname_full = NULL;
+ char *fullname = NULL;
+ bool do_break = true;
+ NTSTATUS status;
+
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+
+ if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
+ false)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+
+ /* Construct the full name. */
+ fullname = talloc_asprintf(ctx,
+ "%s/%s",
+ smb_dname->base_name,
+ dname);
+ if (!fullname) {
+ errno = ENOMEM;
+ goto err_break;
+ }
+
+ status = create_synthetic_smb_fname(talloc_tos(), fullname,
+ NULL, NULL,
+ &smb_dname_full);
+ if (!NT_STATUS_IS_OK(status)) {
+ goto err_break;
+ }
+
+ if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
+ goto err_break;
+ }
+
+ if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
+ if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
+ goto err_break;
+ }
+ if(SMB_VFS_RMDIR(conn,
+ smb_dname_full->base_name) != 0) {
+ goto err_break;
+ }
+ } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
+ goto err_break;
+ }
+
+ /* Successful iteration. */
+ do_break = false;
+
+ err_break:
+ TALLOC_FREE(smb_dname_full);
+ TALLOC_FREE(fullname);
+ TALLOC_FREE(talloced);
+ if (do_break) {
+ ret = false;
+ break;
+ }
+ }
+ TALLOC_FREE(dir_hnd);
+ return ret;
+}
+
+/****************************************************************************
+ The internals of the rmdir code - called elsewhere.
+****************************************************************************/
+
+static NTSTATUS rmdir_internals(TALLOC_CTX *ctx, files_struct *fsp)
+{
+ connection_struct *conn = fsp->conn;
+ struct smb_filename *smb_dname = fsp->fsp_name;
+ int ret;
+
+ SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
+
+ /* Might be a symlink. */
+ if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+
+ if (S_ISLNK(smb_dname->st.st_ex_mode)) {
+ /* Is what it points to a directory ? */
+ if(SMB_VFS_STAT(conn, smb_dname) != 0) {
+ return map_nt_error_from_unix(errno);
+ }
+ if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
+ return NT_STATUS_NOT_A_DIRECTORY;
+ }
+ ret = SMB_VFS_UNLINK(conn, smb_dname);
+ } else {
+ ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
+ }
+ if (ret == 0) {
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ smb_dname->base_name);
+ return NT_STATUS_OK;
+ }
+
+ if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
+ /*
+ * Check to see if the only thing in this directory are
+ * vetoed files/directories. If so then delete them and
+ * retry. If we fail to delete any of them (and we *don't*
+ * do a recursive delete) then fail the rmdir.
+ */
+ SMB_STRUCT_STAT st;
+ const char *dname = NULL;
+ char *talloced = NULL;
+ long dirpos = 0;
+ struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
+ smb_dname->base_name, NULL,
+ 0);
+
+ if(dir_hnd == NULL) {
+ errno = ENOTEMPTY;
+ goto err;
+ }
+
+ while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
+ &talloced)) != NULL) {
+ if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+ if (!is_visible_file(conn, smb_dname->base_name, dname,
+ &st, false)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+ if(!IS_VETO_PATH(conn, dname)) {
+ TALLOC_FREE(dir_hnd);
+ TALLOC_FREE(talloced);
+ errno = ENOTEMPTY;
+ goto err;
+ }
+ TALLOC_FREE(talloced);
+ }
+
+ /* We only have veto files/directories.
+ * Are we allowed to delete them ? */
+
+ if(!lp_recursive_veto_delete(SNUM(conn))) {
+ TALLOC_FREE(dir_hnd);
+ errno = ENOTEMPTY;
+ goto err;
+ }
+
+ /* Do a recursive delete. */
+ RewindDir(dir_hnd,&dirpos);
+ while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
+ &talloced)) != NULL) {
+ struct smb_filename *smb_dname_full = NULL;
+ char *fullname = NULL;
+ bool do_break = true;
+ NTSTATUS status;
+
+ if (ISDOT(dname) || ISDOTDOT(dname)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+ if (!is_visible_file(conn, smb_dname->base_name, dname,
+ &st, false)) {
+ TALLOC_FREE(talloced);
+ continue;
+ }
+
+ fullname = talloc_asprintf(ctx,
+ "%s/%s",
+ smb_dname->base_name,
+ dname);
+
+ if(!fullname) {
+ errno = ENOMEM;
+ goto err_break;
+ }
+
+ status = create_synthetic_smb_fname(talloc_tos(),
+ fullname, NULL,
+ NULL,
+ &smb_dname_full);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
+ goto err_break;
+ }
+
+ if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
+ goto err_break;
+ }
+ if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
+ if(!recursive_rmdir(ctx, conn,
+ smb_dname_full)) {
+ goto err_break;
+ }
+ if(SMB_VFS_RMDIR(conn,
+ smb_dname_full->base_name) != 0) {
+ goto err_break;
+ }
+ } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
+ goto err_break;
+ }
+
+ /* Successful iteration. */
+ do_break = false;
+
+ err_break:
+ TALLOC_FREE(fullname);
+ TALLOC_FREE(smb_dname_full);
+ TALLOC_FREE(talloced);
+ if (do_break)
+ break;
+ }
+ TALLOC_FREE(dir_hnd);
+ /* Retry the rmdir */
+ ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
+ }
+
+ err:
+
+ if (ret != 0) {
+ DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
+ "%s\n", smb_fname_str_dbg(smb_dname),
+ strerror(errno)));
+ return map_nt_error_from_unix(errno);
+ }
+
+ notify_fname(conn, NOTIFY_ACTION_REMOVED,
+ FILE_NOTIFY_CHANGE_DIR_NAME,
+ smb_dname->base_name);
+
+ return NT_STATUS_OK;
+}
/****************************************************************************
Close a directory opened by an NT SMB call.
@@ -742,8 +999,7 @@ static NTSTATUS close_directory(struct smb_request *req, files_struct *fsp,
TALLOC_FREE(lck);
- status = rmdir_internals(talloc_tos(), fsp->conn,
- fsp->fsp_name);
+ status = rmdir_internals(talloc_tos(), fsp);
DEBUG(5,("close_directory: %s. Delete on close was set - "
"deleting directory returned %s.\n",
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index 101635fb50..030939f524 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -5283,264 +5283,6 @@ void reply_mkdir(struct smb_request *req)
}
/****************************************************************************
- Static function used by reply_rmdir to delete an entire directory
- tree recursively. Return True on ok, False on fail.
-****************************************************************************/
-
-static bool recursive_rmdir(TALLOC_CTX *ctx,
- connection_struct *conn,
- struct smb_filename *smb_dname)
-{
- const char *dname = NULL;
- char *talloced = NULL;
- bool ret = True;
- long offset = 0;
- SMB_STRUCT_STAT st;
- struct smb_Dir *dir_hnd;
-
- SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
-
- dir_hnd = OpenDir(talloc_tos(), conn, smb_dname->base_name, NULL, 0);
- if(dir_hnd == NULL)
- return False;
-
- while((dname = ReadDirName(dir_hnd, &offset, &st, &talloced))) {
- struct smb_filename *smb_dname_full = NULL;
- char *fullname = NULL;
- bool do_break = true;
- NTSTATUS status;
-
- if (ISDOT(dname) || ISDOTDOT(dname)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- if (!is_visible_file(conn, smb_dname->base_name, dname, &st,
- false)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- /* Construct the full name. */
- fullname = talloc_asprintf(ctx,
- "%s/%s",
- smb_dname->base_name,
- dname);
- if (!fullname) {
- errno = ENOMEM;
- goto err_break;
- }
-
- status = create_synthetic_smb_fname(talloc_tos(), fullname,
- NULL, NULL,
- &smb_dname_full);
- if (!NT_STATUS_IS_OK(status)) {
- goto err_break;
- }
-
- if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
- goto err_break;
- }
-
- if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
- if(!recursive_rmdir(ctx, conn, smb_dname_full)) {
- goto err_break;
- }
- if(SMB_VFS_RMDIR(conn,
- smb_dname_full->base_name) != 0) {
- goto err_break;
- }
- } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
- goto err_break;
- }
-
- /* Successful iteration. */
- do_break = false;
-
- err_break:
- TALLOC_FREE(smb_dname_full);
- TALLOC_FREE(fullname);
- TALLOC_FREE(talloced);
- if (do_break) {
- ret = false;
- break;
- }
- }
- TALLOC_FREE(dir_hnd);
- return ret;
-}
-
-/****************************************************************************
- The internals of the rmdir code - called elsewhere.
-****************************************************************************/
-
-NTSTATUS rmdir_internals(TALLOC_CTX *ctx,
- connection_struct *conn,
- struct smb_filename *smb_dname)
-{
- int ret;
-
- SMB_ASSERT(!is_ntfs_stream_smb_fname(smb_dname));
-
- /* Might be a symlink. */
- if(SMB_VFS_LSTAT(conn, smb_dname) != 0) {
- return map_nt_error_from_unix(errno);
- }
-
- if (S_ISLNK(smb_dname->st.st_ex_mode)) {
- /* Is what it points to a directory ? */
- if(SMB_VFS_STAT(conn, smb_dname) != 0) {
- return map_nt_error_from_unix(errno);
- }
- if (!(S_ISDIR(smb_dname->st.st_ex_mode))) {
- return NT_STATUS_NOT_A_DIRECTORY;
- }
- ret = SMB_VFS_UNLINK(conn, smb_dname);
- } else {
- ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
- }
- if (ret == 0) {
- notify_fname(conn, NOTIFY_ACTION_REMOVED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- smb_dname->base_name);
- return NT_STATUS_OK;
- }
-
- if(((errno == ENOTEMPTY)||(errno == EEXIST)) && lp_veto_files(SNUM(conn))) {
- /*
- * Check to see if the only thing in this directory are
- * vetoed files/directories. If so then delete them and
- * retry. If we fail to delete any of them (and we *don't*
- * do a recursive delete) then fail the rmdir.
- */
- SMB_STRUCT_STAT st;
- const char *dname = NULL;
- char *talloced = NULL;
- long dirpos = 0;
- struct smb_Dir *dir_hnd = OpenDir(talloc_tos(), conn,
- smb_dname->base_name, NULL,
- 0);
-
- if(dir_hnd == NULL) {
- errno = ENOTEMPTY;
- goto err;
- }
-
- while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
- &talloced)) != NULL) {
- if((strcmp(dname, ".") == 0) || (strcmp(dname, "..")==0)) {
- TALLOC_FREE(talloced);
- continue;
- }
- if (!is_visible_file(conn, smb_dname->base_name, dname,
- &st, false)) {
- TALLOC_FREE(talloced);
- continue;
- }
- if(!IS_VETO_PATH(conn, dname)) {
- TALLOC_FREE(dir_hnd);
- TALLOC_FREE(talloced);
- errno = ENOTEMPTY;
- goto err;
- }
- TALLOC_FREE(talloced);
- }
-
- /* We only have veto files/directories.
- * Are we allowed to delete them ? */
-
- if(!lp_recursive_veto_delete(SNUM(conn))) {
- TALLOC_FREE(dir_hnd);
- errno = ENOTEMPTY;
- goto err;
- }
-
- /* Do a recursive delete. */
- RewindDir(dir_hnd,&dirpos);
- while ((dname = ReadDirName(dir_hnd, &dirpos, &st,
- &talloced)) != NULL) {
- struct smb_filename *smb_dname_full = NULL;
- char *fullname = NULL;
- bool do_break = true;
- NTSTATUS status;
-
- if (ISDOT(dname) || ISDOTDOT(dname)) {
- TALLOC_FREE(talloced);
- continue;
- }
- if (!is_visible_file(conn, smb_dname->base_name, dname,
- &st, false)) {
- TALLOC_FREE(talloced);
- continue;
- }
-
- fullname = talloc_asprintf(ctx,
- "%s/%s",
- smb_dname->base_name,
- dname);
-
- if(!fullname) {
- errno = ENOMEM;
- goto err_break;
- }
-
- status = create_synthetic_smb_fname(talloc_tos(),
- fullname, NULL,
- NULL,
- &smb_dname_full);
- if (!NT_STATUS_IS_OK(status)) {
- errno = map_errno_from_nt_status(status);
- goto err_break;
- }
-
- if(SMB_VFS_LSTAT(conn, smb_dname_full) != 0) {
- goto err_break;
- }
- if(smb_dname_full->st.st_ex_mode & S_IFDIR) {
- if(!recursive_rmdir(ctx, conn,
- smb_dname_full)) {
- goto err_break;
- }
- if(SMB_VFS_RMDIR(conn,
- smb_dname_full->base_name) != 0) {
- goto err_break;
- }
- } else if(SMB_VFS_UNLINK(conn, smb_dname_full) != 0) {
- goto err_break;
- }
-
- /* Successful iteration. */
- do_break = false;
-
- err_break:
- TALLOC_FREE(fullname);
- TALLOC_FREE(smb_dname_full);
- TALLOC_FREE(talloced);
- if (do_break)
- break;
- }
- TALLOC_FREE(dir_hnd);
- /* Retry the rmdir */
- ret = SMB_VFS_RMDIR(conn, smb_dname->base_name);
- }
-
- err:
-
- if (ret != 0) {
- DEBUG(3,("rmdir_internals: couldn't remove directory %s : "
- "%s\n", smb_fname_str_dbg(smb_dname),
- strerror(errno)));
- return map_nt_error_from_unix(errno);
- }
-
- notify_fname(conn, NOTIFY_ACTION_REMOVED,
- FILE_NOTIFY_CHANGE_DIR_NAME,
- smb_dname->base_name);
-
- return NT_STATUS_OK;
-}
-
-/****************************************************************************
Reply to a rmdir.
****************************************************************************/
@@ -5551,6 +5293,8 @@ void reply_rmdir(struct smb_request *req)
char *directory = NULL;
NTSTATUS status;
TALLOC_CTX *ctx = talloc_tos();
+ files_struct *fsp = NULL;
+ int info = 0;
struct smbd_server_connection *sconn = smbd_server_conn;
START_PROFILE(SMBrmdir);
@@ -5583,15 +5327,51 @@ void reply_rmdir(struct smb_request *req)
goto out;
}
- dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
- status = rmdir_internals(ctx, conn, smb_dname);
+ status = SMB_VFS_CREATE_FILE(
+ conn, /* conn */
+ req, /* req */
+ 0, /* root_dir_fid */
+ smb_dname, /* fname */
+ DELETE_ACCESS, /* access_mask */
+ (FILE_SHARE_READ | FILE_SHARE_WRITE | /* share_access */
+ FILE_SHARE_DELETE),
+ FILE_OPEN, /* create_disposition*/
+ FILE_DIRECTORY_FILE, /* create_options */
+ FILE_ATTRIBUTE_DIRECTORY, /* file_attributes */
+ 0, /* oplock_request */
+ 0, /* allocation_size */
+ NULL, /* sd */
+ NULL, /* ea_list */
+ &fsp, /* result */
+ &info); /* pinfo */
+
if (!NT_STATUS_IS_OK(status)) {
+ if (open_was_deferred(req->mid)) {
+ /* We have re-scheduled this call. */
+ goto out;
+ }
reply_nterror(req, status);
goto out;
}
+ status = can_set_delete_on_close(fsp, FILE_ATTRIBUTE_DIRECTORY);
+ if (!NT_STATUS_IS_OK(status)) {
+ close_file(req, fsp, ERROR_CLOSE);
+ reply_nterror(req, status);
+ goto out;
+ }
+
+ if (!set_delete_on_close(fsp, true, &conn->server_info->utok)) {
+ close_file(req, fsp, ERROR_CLOSE);
+ reply_nterror(req, NT_STATUS_ACCESS_DENIED);
+ goto out;
+ }
+
+ close_file(req, fsp, NORMAL_CLOSE);
reply_outbuf(req, 0, 0);
+ dptr_closepath(sconn, smb_dname->base_name, req->smbpid);
+
DEBUG(3, ("rmdir %s\n", smb_fname_str_dbg(smb_dname)));
out:
TALLOC_FREE(smb_dname);