-
Notifications
You must be signed in to change notification settings - Fork 61
/
815-smb2-recvfile.patch
471 lines (403 loc) · 14.1 KB
/
815-smb2-recvfile.patch
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
From cac4112c1a482e78dc06f993c67bf05f1501b104 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 18 Mar 2013 12:00:25 -0700
Subject: [PATCH 01/10] Ensure we don't do an SMB2 aio write if RECVFILE is
active.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/aio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/source3/smbd/aio.c b/source3/smbd/aio.c
index 3f553eb..e8be408 100644
--- a/source3/smbd/aio.c
+++ b/source3/smbd/aio.c
@@ -861,6 +861,11 @@ NTSTATUS schedule_aio_smb2_write(connection_struct *conn,
return NT_STATUS_RETRY;
}
+ if (smbreq->unread_bytes) {
+ /* Can't do async with recvfile. */
+ return NT_STATUS_RETRY;
+ }
+
if (!(aio_ex = create_aio_extra(smbreq->smb2req, fsp, 0))) {
return NT_STATUS_NO_MEMORY;
}
--
1.8.1.3
From 72152d0cf1c601de2df775153ca25e8ee9acdc93 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Mar 2013 12:16:32 -0700
Subject: [PATCH 02/10] If we already have an smb1req attached to the struct
smbd_smb2_request, don't recreate it.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_glue.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 1b2b4dd..9fc1e49 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -28,9 +28,13 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
struct smb_request *smbreq;
const uint8_t *inhdr = SMBD_SMB2_IN_HDR_PTR(req);
- smbreq = talloc_zero(req, struct smb_request);
- if (smbreq == NULL) {
- return NULL;
+ if (req->smb1req) {
+ smbreq = req->smb1req;
+ } else {
+ smbreq = talloc_zero(req, struct smb_request);
+ if (smbreq == NULL) {
+ return NULL;
+ }
}
smbreq->request_time = req->request_time;
--
1.8.1.3
From 5ee20571db56dd538c6aa96acf93fc298ca243e6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Mar 2013 12:24:17 -0700
Subject: [PATCH 03/10] Add function smbd_smb2_unread_bytes().
Returns number of bytes left to read for recvfile. Will be
used in SMB_2_WRITE_FILE code path.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/globals.h | 1 +
source3/smbd/smb2_glue.c | 12 ++++++++++++
2 files changed, 13 insertions(+)
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 3461bc5..a0a04bb 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -247,6 +247,7 @@ NTSTATUS smbd_smb2_request_pending_queue(struct smbd_smb2_request *req,
uint32_t defer_time);
struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req);
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req);
void remove_smb2_chained_fsp(files_struct *fsp);
NTSTATUS smbd_smb2_request_verify_creditcharge(struct smbd_smb2_request *req,
diff --git a/source3/smbd/smb2_glue.c b/source3/smbd/smb2_glue.c
index 9fc1e49..23d6ce5 100644
--- a/source3/smbd/smb2_glue.c
+++ b/source3/smbd/smb2_glue.c
@@ -59,6 +59,18 @@ struct smb_request *smbd_smb2_fake_smb_request(struct smbd_smb2_request *req)
}
/*********************************************************
+ Are there unread bytes for recvfile ?
+*********************************************************/
+
+size_t smbd_smb2_unread_bytes(struct smbd_smb2_request *req)
+{
+ if (req->smb1req && req->smb1req->unread_bytes) {
+ return req->smb1req->unread_bytes;
+ }
+ return 0;
+}
+
+/*********************************************************
Called from file_free() to remove any chained fsp pointers.
*********************************************************/
--
1.8.1.3
From 3cfe0507b2bd0b87a51aef81c6aa07557fa8c2e3 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Tue, 19 Mar 2013 12:36:52 -0700
Subject: [PATCH 04/10] Allow smbd_smb2_request_error_ex() to cope with unread
bytes on error.
Drain the socket if a RECVFILE write failed.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index eb7059e..edd54cc 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2621,11 +2621,20 @@ NTSTATUS smbd_smb2_request_error_ex(struct smbd_smb2_request *req,
{
DATA_BLOB body;
uint8_t *outhdr = SMBD_SMB2_OUT_HDR_PTR(req);
+ size_t unread_bytes = smbd_smb2_unread_bytes(req);
DEBUG(10,("smbd_smb2_request_error_ex: idx[%d] status[%s] |%s| at %s\n",
req->current_idx, nt_errstr(status), info ? " +info" : "",
location));
+ if (unread_bytes) {
+ /* Recvfile error. Drain incoming socket. */
+ if (drain_socket(req->sconn->sock, unread_bytes) !=
+ unread_bytes) {
+ smb_panic("Failed to drain SMB2 socket\n");
+ }
+ }
+
body.data = outhdr + SMB2_HDR_BODY;
body.length = 8;
SSVAL(body.data, 0, 9);
--
1.8.1.3
From d4a5b72d2a759f1a7ae3f5884ec6211ea4d8c076 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 13:12:55 -0700
Subject: [PATCH 05/10] Add utility function get_min_receive_file_size().
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index edd54cc..a401c63 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2841,6 +2841,17 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
size_t *_count);
static void smbd_smb2_request_read_done(struct tevent_req *subreq);
+static size_t get_min_receive_file_size(struct smbd_smb2_request *smb2_req)
+{
+ if (smb2_req->do_signing) {
+ return 0;
+ }
+ if (smb2_req->do_encryption) {
+ return 0;
+ }
+ return (size_t)lp_min_receive_file_size();
+}
+
static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
struct smbd_server_connection *sconn)
--
1.8.1.3
From af6197f591c04d8d49ab7a3475b5956706109165 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 13:14:13 -0700
Subject: [PATCH 06/10] Add macro SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN.
This is the 'short' length we'll read in the SMB2_WRITE receivefile
code path.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/globals.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index a0a04bb..f075a6d 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -546,6 +546,8 @@ struct smbd_smb2_request {
#define SMBD_SMB2_OUT_DYN_PTR(req) (uint8_t *)(SMBD_SMB2_OUT_DYN_IOV(req)->iov_base)
#define SMBD_SMB2_OUT_DYN_LEN(req) (SMBD_SMB2_OUT_DYN_IOV(req)->iov_len)
+#define SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN (SMB2_HDR_BODY + 0x30)
+
struct {
/*
* vector[0] TRANSPORT HEADER (empty)
--
1.8.1.3
From 2525fd05ff68e4a69648bddef91062c1d701185a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 13:17:09 -0700
Subject: [PATCH 07/10] Add extra fields into struct
smbd_smb2_request_read_state to support receivefile.
Initialize min_recv_size with the size that will trigger the
receivefile write path.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index a401c63..4d0d67c 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2830,6 +2830,8 @@ struct smbd_smb2_request_read_state {
uint8_t nbt[NBT_HDR_SIZE];
bool done;
} hdr;
+ bool doing_receivefile;
+ size_t min_recv_size;
size_t pktlen;
uint8_t *pktbuf;
};
@@ -2873,6 +2875,7 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
state->smb2_req->sconn = sconn;
+ state->min_recv_size = get_min_receive_file_size(state->smb2_req);
subreq = tstream_readv_pdu_queue_send(state->smb2_req,
state->ev,
--
1.8.1.3
From d1e1f179fc79ddf497e6bf0a35ea303d3cded5f5 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 13:19:01 -0700
Subject: [PATCH 08/10] Add stub static function that will turn on/off
receivefile code path.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 4d0d67c..7660ab7 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2891,6 +2891,11 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
return req;
}
+static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
+{
+ return false;
+}
+
static int smbd_smb2_request_next_vector(struct tstream_context *stream,
void *private_data,
TALLOC_CTX *mem_ctx,
--
1.8.1.3
From 9bacecc9686df7d4d9249676bfcacd27e1cf3720 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 13:24:07 -0700
Subject: [PATCH 09/10] The guts of the receivefile code changes.
If an incoming PDU might qualify, only read
SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN (SMB2_HEADER + SMB2_WRITE_BODY_LEN) +
state->min_recv_size bytes rather than the whole PDU.
Next time we're called, use is_smb2_recvfile_write() to decide if
this is an SMB2_WRITE that fit the receivefile criteria, otherwise
just read the rest of the PDU.
If we did do a short receivefile read, set up the smb2_req->smb1req->unread_bytes
value to show what bytes remain in the TCP buffers.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 59 ++++++++++++++++++++++++++++++++++++++++++----
1 file changed, 54 insertions(+), 5 deletions(-)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 7660ab7..6aae9c8 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2905,12 +2905,36 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
struct smbd_smb2_request_read_state *state =
talloc_get_type_abort(private_data,
struct smbd_smb2_request_read_state);
- struct iovec *vector;
+ struct iovec *vector = NULL;
if (state->pktlen > 0) {
- /* if there're no remaining bytes, we're done */
- *_vector = NULL;
- *_count = 0;
+ if (state->doing_receivefile && !is_smb2_recvfile_write(state)) {
+ /*
+ * Not a possible receivefile write.
+ * Read the rest of the data.
+ */
+ state->doing_receivefile = false;
+ vector = talloc_array(mem_ctx, struct iovec, 1);
+ if (vector == NULL) {
+ return -1;
+ }
+ vector[0].iov_base = (void *)(state->pktbuf +
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+ vector[0].iov_len = (state->pktlen -
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN);
+ *_vector = vector;
+ *_count = 1;
+ } else {
+ /*
+ * Either this is a receivefile write so we've
+ * done a short read, or if not we have all the data.
+ * Either way, we're done and the caller will handle
+ * and short read case by looking at the
+ * state->doing_receivefile value.
+ */
+ *_vector = NULL;
+ *_count = 0;
+ }
return 0;
}
@@ -2956,7 +2980,22 @@ static int smbd_smb2_request_next_vector(struct tstream_context *stream,
}
vector[0].iov_base = (void *)state->pktbuf;
- vector[0].iov_len = state->pktlen;
+ if (state->min_recv_size &&
+ state->pktlen > SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN +
+ state->min_recv_size) {
+ /*
+ * Might be a receivefile write. Read the SMB2 HEADER +
+ * SMB2_WRITE header first. Set 'doing_receivefile'
+ * as we're *attempting* receivefile write. If this
+ * turns out not to be a SMB2_WRITE request or otherwise
+ * not suitable then we'll just read the rest of the data
+ * the next time this function is called.
+ */
+ vector[0].iov_len = SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+ state->doing_receivefile = true;
+ } else {
+ vector[0].iov_len = state->pktlen;
+ }
*_vector = vector;
*_count = 1;
@@ -3019,6 +3058,16 @@ static void smbd_smb2_request_read_done(struct tevent_req *subreq)
return;
}
+ if (state->doing_receivefile) {
+ state->smb2_req->smb1req = talloc_zero(state->smb2_req,
+ struct smb_request);
+ if (tevent_req_nomem(state->smb2_req->smb1req, req)) {
+ return;
+ }
+ state->smb2_req->smb1req->unread_bytes =
+ state->pktlen - SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN;
+ }
+
state->smb2_req->current_idx = 1;
tevent_req_done(req);
--
1.8.1.3
From ccbb3939c2a47c71042cfacc76da2803448ccef6 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra@samba.org>
Date: Mon, 1 Apr 2013 11:16:01 -0700
Subject: [PATCH 10/10] Add the internals of is_smb2_recvfile_write.
This turns on the real receivefile detection, and completes
the receivefile code path changes.
Signed-off-by: Jeremy Allison <jra@samba.org>
---
source3/smbd/smb2_server.c | 35 ++++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/source3/smbd/smb2_server.c b/source3/smbd/smb2_server.c
index 6aae9c8..66c59af 100644
--- a/source3/smbd/smb2_server.c
+++ b/source3/smbd/smb2_server.c
@@ -2893,7 +2893,40 @@ static struct tevent_req *smbd_smb2_request_read_send(TALLOC_CTX *mem_ctx,
static bool is_smb2_recvfile_write(struct smbd_smb2_request_read_state *state)
{
- return false;
+ if (IVAL(state->pktbuf, 0) == SMB2_TF_MAGIC) {
+ /* Transform header. Cannot recvfile. */
+ return false;
+ }
+
+ if (IVAL(state->pktbuf, 0) != SMB2_MAGIC) {
+ /* Not SMB2. Normal error path will cope. */
+ return false;
+ }
+ if (SVAL(state->pktbuf, 4) != SMB2_HDR_BODY) {
+ /* Not SMB2. Normal error path will cope. */
+ return false;
+ }
+ if (IVAL(state->pktbuf, SMB2_HDR_NEXT_COMMAND) != 0) {
+ /* Chained. Cannot recvfile. */
+ return false;
+ }
+ if (IVAL(state->pktbuf, SMB2_HDR_FLAGS) &
+ (SMB2_HDR_FLAG_CHAINED|
+ SMB2_HDR_FLAG_SIGNED)) {
+ /* Signed or chained. Cannot recvfile. */
+ return false;
+ }
+
+ if (SVAL(state->pktbuf, SMB2_HDR_OPCODE) != SMB2_OP_WRITE) {
+ /* Needs to be a WRITE. */
+ return false;
+ }
+
+ DEBUG(10,("Doing recvfile write len = %u!\n",
+ (unsigned int)(state->pktlen -
+ SMBD_SMB2_SHORT_RECEIVEFILE_WRITE_LEN)));
+
+ return true;
}
static int smbd_smb2_request_next_vector(struct tstream_context *stream,
--
1.8.1.3