Package: samba / 2:4.5.16+dfsg-1+deb9u2

fix-rmdir.patch Patch series | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
From: Stefan Metzmacher <metze@samba.org>
Date: Tue, 20 Jun 2017 08:35:13 +0200
Subject: s3:libsmb: add cli_smb2_delete_on_close*()

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
(cherry picked from commit 8d4005b07b08d5673b75d5d79f9b3d6936596fae)

diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 43f116b681d..674c52e4405 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -484,6 +484,133 @@ NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum)
 	return status;
 }
 
+struct cli_smb2_delete_on_close_state {
+	struct cli_state *cli;
+	uint16_t fnum;
+	struct smb2_hnd *ph;
+	uint8_t data[1];
+	DATA_BLOB inbuf;
+};
+
+static void cli_smb2_delete_on_close_done(struct tevent_req *subreq);
+
+struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct cli_state *cli,
+					uint16_t fnum,
+					bool flag)
+{
+	struct tevent_req *req = NULL;
+	struct cli_smb2_delete_on_close_state *state = NULL;
+	struct tevent_req *subreq = NULL;
+	uint8_t in_info_type;
+	uint8_t in_file_info_class;
+	NTSTATUS status;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct cli_smb2_delete_on_close_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->cli = cli;
+	state->fnum = fnum;
+
+	if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		return tevent_req_post(req, ev);
+	}
+
+	status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
+	if (tevent_req_nterror(req, status)) {
+		return tevent_req_post(req, ev);
+	}
+
+	/*
+	 * setinfo on the handle with info_type SMB2_SETINFO_FILE (1),
+	 * level 13 (SMB_FILE_DISPOSITION_INFORMATION - 1000).
+	 */
+	in_info_type = 1;
+	in_file_info_class = SMB_FILE_DISPOSITION_INFORMATION - 1000;
+	/* Setup data array. */
+	SCVAL(&state->data[0], 0, flag ? 1 : 0);
+	state->inbuf.data = &state->data[0];
+	state->inbuf.length = 1;
+
+	subreq = smb2cli_set_info_send(state, ev,
+				       cli->conn,
+				       cli->timeout,
+				       cli->smb2.session,
+				       cli->smb2.tcon,
+				       in_info_type,
+				       in_file_info_class,
+				       &state->inbuf, /* in_input_buffer */
+				       0, /* in_additional_info */
+				       state->ph->fid_persistent,
+				       state->ph->fid_volatile);
+	if (tevent_req_nomem(subreq, req)) {
+		return tevent_req_post(req, ev);
+	}
+	tevent_req_set_callback(subreq,
+				cli_smb2_delete_on_close_done,
+				req);
+	return req;
+}
+
+static void cli_smb2_delete_on_close_done(struct tevent_req *subreq)
+{
+	NTSTATUS status = smb2cli_set_info_recv(subreq);
+	tevent_req_simple_finish_ntstatus(subreq, status);
+}
+
+NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req)
+{
+	struct cli_smb2_delete_on_close_state *state =
+		tevent_req_data(req,
+		struct cli_smb2_delete_on_close_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status)) {
+		state->cli->raw_status = status;
+		tevent_req_received(req);
+		return status;
+	}
+
+	state->cli->raw_status = NT_STATUS_OK;
+	tevent_req_received(req);
+	return NT_STATUS_OK;
+}
+
+NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag)
+{
+	TALLOC_CTX *frame = talloc_stackframe();
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+	if (smbXcli_conn_has_async_calls(cli->conn)) {
+		/*
+		 * Can't use sync call while an async call is in flight
+		 */
+		status = NT_STATUS_INVALID_PARAMETER;
+		goto fail;
+	}
+	ev = samba_tevent_context_init(frame);
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = cli_smb2_delete_on_close_send(frame, ev, cli, fnum, flag);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+		goto fail;
+	}
+	status = cli_smb2_delete_on_close_recv(req);
+ fail:
+	TALLOC_FREE(frame);
+	return status;
+}
+
 /***************************************************************
  Small wrapper that allows SMB2 to create a directory
  Synchronous only.
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index 435a5c28db3..b7d64f1da4d 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -54,6 +54,13 @@ struct tevent_req *cli_smb2_close_fnum_send(TALLOC_CTX *mem_ctx,
 					    uint16_t fnum);
 NTSTATUS cli_smb2_close_fnum_recv(struct tevent_req *req);
 NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum);
+struct tevent_req *cli_smb2_delete_on_close_send(TALLOC_CTX *mem_ctx,
+					struct tevent_context *ev,
+					struct cli_state *cli,
+					uint16_t fnum,
+					bool flag);
+NTSTATUS cli_smb2_delete_on_close_recv(struct tevent_req *req);
+NTSTATUS cli_smb2_delete_on_close(struct cli_state *cli, uint16_t fnum, bool flag);
 NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dirname);
 NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dirname);
 NTSTATUS cli_smb2_unlink(struct cli_state *cli,const char *fname);
-- 
2.20.1

From: Anoop C S <anoopcs@redhat.com>
Date: Thu, 9 Aug 2018 12:28:41 +0530
Subject: s3/libsmb: Explicitly set delete_on_close token for rmdir

The current implementation of `rmdir` hopes to get the directory deleted
on closing last open handle when FILE_DELETE_ON_CLOSE is set on it. But
for non-empty directories Windows doesn't error out during an open call.
Following that we internally refuse to set initial delete_on_close while
opening a non-empty directory. This prevents us from trying to delete
the directory when last open handle is closed.

Instead of relying on FILE_DELETE_ON_CLOSE during an open we explicitly
set delete_on_close token on directory handle once it is available. This
ensures that NT_STATUS_DIRECTORY_NOT_EMPTY is returned for `rmdir` on
non-empty directories while closing open directory handle.

Applied-Upstream: https://github.com/samba-team/samba/commit/6b68e3eca631c04d6d57c489daf60f64732fc86d
Bug: https://bugzilla.samba.org/show_bug.cgi?id=13204
Bug-Debian: https://bugs.debian.org/915248
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/samba/+bug/1795772

diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index fc99be23d03..43f116b681d 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -550,13 +550,20 @@ NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
 			FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
 			FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
 			FILE_OPEN,		/* create_disposition */
-			FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE,	/* create_options */
+			FILE_DIRECTORY_FILE,	/* create_options */
 			&fnum,
 			NULL);
 
 	if (!NT_STATUS_IS_OK(status)) {
 		return status;
 	}
+
+	status = cli_smb2_delete_on_close(cli, fnum, true);
+	if (!NT_STATUS_IS_OK(status)) {
+		cli_smb2_close_fnum(cli, fnum);
+		return status;
+	}
+
 	return cli_smb2_close_fnum(cli, fnum);
 }
 
-- 
2.20.1