Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : SMB2 client request handling
5 :
6 : Copyright (C) Andrew Tridgell 2005
7 : Copyright (C) Stefan Metzmacher 2005
8 :
9 : This program is free software; you can redistribute it and/or modify
10 : it under the terms of the GNU General Public License as published by
11 : the Free Software Foundation; either version 3 of the License, or
12 : (at your option) any later version.
13 :
14 : This program is distributed in the hope that it will be useful,
15 : but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : GNU General Public License for more details.
18 :
19 : You should have received a copy of the GNU General Public License
20 : along with this program. If not, see <http://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "includes.h"
24 : #include "libcli/raw/libcliraw.h"
25 : #include "libcli/smb2/smb2.h"
26 : #include "../lib/util/dlinklist.h"
27 : #include "lib/events/events.h"
28 : #include "libcli/smb2/smb2_calls.h"
29 :
30 : /* fill in the bufinfo */
31 1159518 : void smb2_setup_bufinfo(struct smb2_request *req)
32 : {
33 1159518 : req->in.bufinfo.mem_ctx = req;
34 1159518 : req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
35 1159518 : req->in.bufinfo.align_base = req->in.buffer;
36 1159518 : if (req->in.dynamic) {
37 1159518 : req->in.bufinfo.data = req->in.dynamic;
38 1159518 : req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed;
39 : } else {
40 0 : req->in.bufinfo.data = NULL;
41 0 : req->in.bufinfo.data_size = 0;
42 : }
43 1159518 : }
44 :
45 : /*
46 : initialise a smb2 request
47 : */
48 1159668 : struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
49 : uint16_t body_fixed_size, bool body_dynamic_present,
50 : uint32_t body_dynamic_size)
51 : {
52 898 : struct smb2_request *req;
53 898 : uint32_t hdr_offset;
54 1159668 : bool compound = false;
55 :
56 1159668 : if (body_dynamic_present) {
57 701623 : if (body_dynamic_size == 0) {
58 638570 : body_dynamic_size = 1;
59 : }
60 : } else {
61 457848 : body_dynamic_size = 0;
62 : }
63 :
64 1159668 : req = talloc_zero(transport, struct smb2_request);
65 1159668 : if (req == NULL) return NULL;
66 :
67 1159668 : req->state = SMB2_REQUEST_INIT;
68 1159668 : req->transport = transport;
69 :
70 1159668 : hdr_offset = NBT_HDR_SIZE;
71 :
72 1159668 : req->out.size = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
73 1159668 : req->out.allocated = req->out.size + body_dynamic_size;
74 :
75 1159668 : req->out.buffer = talloc_realloc(req, req->out.buffer,
76 : uint8_t, req->out.allocated);
77 1159668 : if (req->out.buffer == NULL) {
78 0 : talloc_free(req);
79 0 : return NULL;
80 : }
81 :
82 1159668 : req->out.hdr = req->out.buffer + hdr_offset;
83 1159668 : req->out.body = req->out.hdr + SMB2_HDR_BODY;
84 1159668 : req->out.body_fixed= body_fixed_size;
85 1159668 : req->out.body_size = body_fixed_size;
86 1159668 : req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
87 :
88 1159668 : SIVAL(req->out.hdr, 0, SMB2_MAGIC);
89 1159668 : SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
90 1159668 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE, 0);
91 1159668 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
92 1159668 : SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
93 1159668 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
94 1159668 : SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
95 1159668 : SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
96 1159668 : SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, 0);
97 1159668 : SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
98 1159668 : SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
99 1159668 : SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
100 1159668 : memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
101 :
102 : /* set the length of the fixed body part and +1 if there's a dynamic part also */
103 1159865 : SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
104 :
105 : /*
106 : * if we have a dynamic part, make sure the first byte
107 : * which is always be part of the packet is initialized
108 : */
109 1159668 : if (body_dynamic_size && !compound) {
110 701623 : req->out.size += 1;
111 701623 : SCVAL(req->out.dynamic, 0, 0);
112 : }
113 :
114 1158770 : return req;
115 : }
116 :
117 : /*
118 : initialise a smb2 request for tree operations
119 : */
120 1158610 : struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
121 : uint16_t body_fixed_size, bool body_dynamic_present,
122 : uint32_t body_dynamic_size)
123 : {
124 1158610 : struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
125 : body_fixed_size, body_dynamic_present,
126 : body_dynamic_size);
127 1158610 : if (req == NULL) return NULL;
128 :
129 1158610 : req->session = tree->session;
130 1158610 : req->tree = tree;
131 :
132 1158610 : return req;
133 : }
134 :
135 : /* destroy a request structure and return final status */
136 1159562 : NTSTATUS smb2_request_destroy(struct smb2_request *req)
137 : {
138 898 : NTSTATUS status;
139 :
140 : /* this is the error code we give the application for when a
141 : _send() call fails completely */
142 1159562 : if (!req) return NT_STATUS_UNSUCCESSFUL;
143 :
144 1159562 : if (req->state == SMB2_REQUEST_ERROR &&
145 58 : NT_STATUS_IS_OK(req->status)) {
146 0 : status = NT_STATUS_INTERNAL_ERROR;
147 : } else {
148 1159562 : status = req->status;
149 : }
150 :
151 1159562 : talloc_free(req);
152 1159562 : return status;
153 : }
154 :
155 : /*
156 : receive a response to a packet
157 : */
158 1159605 : bool smb2_request_receive(struct smb2_request *req)
159 : {
160 : /* req can be NULL when a send has failed. This eliminates lots of NULL
161 : checks in each module */
162 1159605 : if (!req) return false;
163 :
164 : /* keep receiving packets until this one is replied to */
165 3400598 : while (req->state <= SMB2_REQUEST_RECV) {
166 2240993 : if (tevent_loop_once(req->transport->ev) != 0) {
167 0 : return false;
168 : }
169 : }
170 :
171 1159605 : return req->state == SMB2_REQUEST_DONE;
172 : }
173 :
174 : /* Return true if the last packet was in error */
175 20620 : bool smb2_request_is_error(struct smb2_request *req)
176 : {
177 20620 : return NT_STATUS_IS_ERR(req->status);
178 : }
179 :
180 : /* Return true if the last packet was OK */
181 1137253 : bool smb2_request_is_ok(struct smb2_request *req)
182 : {
183 1137253 : return NT_STATUS_IS_OK(req->status);
184 : }
185 :
186 : /*
187 : check if a range in the reply body is out of bounds
188 : */
189 3167018 : bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
190 : {
191 3167018 : if (size == 0) {
192 : /* zero bytes is never out of range */
193 56943 : return false;
194 : }
195 : /* be careful with wraparound! */
196 3110075 : if ((uintptr_t)ptr < (uintptr_t)buf->body ||
197 3110075 : (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
198 3110075 : size > buf->body_size ||
199 3110075 : (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
200 0 : return true;
201 : }
202 3108222 : return false;
203 : }
204 :
205 742001 : size_t smb2_padding_size(uint32_t offset, size_t n)
206 : {
207 742001 : if ((offset & (n-1)) == 0) return 0;
208 2116 : return n - (offset & (n-1));
209 : }
210 :
211 742001 : static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
212 : {
213 742001 : if (buf->dynamic == (buf->body + buf->body_fixed)) {
214 739184 : if (buf->dynamic != (buf->buffer + buf->size)) {
215 739039 : return 1;
216 : }
217 : }
218 2962 : return 0;
219 : }
220 :
221 : /*
222 : grow a SMB2 buffer by the specified amount
223 : */
224 773439 : NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
225 : {
226 391 : size_t hdr_ofs;
227 391 : size_t dynamic_ofs;
228 391 : uint8_t *buffer_ptr;
229 773439 : uint32_t newsize = buf->size + increase;
230 :
231 : /* a packet size should be limited a bit */
232 773439 : if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
233 :
234 773439 : if (newsize <= buf->allocated) return NT_STATUS_OK;
235 :
236 641501 : hdr_ofs = buf->hdr - buf->buffer;
237 641501 : dynamic_ofs = buf->dynamic - buf->buffer;
238 :
239 641501 : buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
240 641501 : NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
241 :
242 641501 : buf->buffer = buffer_ptr;
243 641501 : buf->hdr = buf->buffer + hdr_ofs;
244 641501 : buf->body = buf->hdr + SMB2_HDR_BODY;
245 641501 : buf->dynamic = buf->buffer + dynamic_ofs;
246 641501 : buf->allocated = newsize;
247 :
248 641501 : return NT_STATUS_OK;
249 : }
250 :
251 : /*
252 : pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
253 : the ptr points to the start of the offset/length pair
254 : */
255 226655 : NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
256 : {
257 306 : uint16_t ofs, size;
258 226655 : if (smb2_oob(buf, ptr, 4)) {
259 0 : return NT_STATUS_INVALID_PARAMETER;
260 : }
261 226655 : ofs = SVAL(ptr, 0);
262 226655 : size = SVAL(ptr, 2);
263 226655 : if (ofs == 0) {
264 25 : *blob = data_blob(NULL, 0);
265 25 : return NT_STATUS_OK;
266 : }
267 226630 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
268 0 : return NT_STATUS_INVALID_PARAMETER;
269 : }
270 226630 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
271 226630 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
272 226630 : return NT_STATUS_OK;
273 : }
274 :
275 : /*
276 : push a uint16_t ofs/ uint16_t length/blob triple into a data blob
277 : the ofs points to the start of the offset/length pair, and is relative
278 : to the body start
279 : */
280 626432 : NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
281 : uint16_t ofs, DATA_BLOB blob)
282 : {
283 367 : NTSTATUS status;
284 367 : size_t offset;
285 367 : size_t padding_length;
286 367 : size_t padding_fix;
287 626432 : uint8_t *ptr = buf->body+ofs;
288 :
289 626432 : if (buf->dynamic == NULL) {
290 0 : return NT_STATUS_INVALID_PARAMETER;
291 : }
292 :
293 : /* we have only 16 bit for the size */
294 626432 : if (blob.length > 0xFFFF) {
295 0 : return NT_STATUS_INVALID_PARAMETER;
296 : }
297 :
298 : /* check if there're enough room for ofs and size */
299 626432 : if (smb2_oob(buf, ptr, 4)) {
300 0 : return NT_STATUS_INVALID_PARAMETER;
301 : }
302 :
303 626432 : if (blob.data == NULL) {
304 0 : if (blob.length != 0) {
305 0 : return NT_STATUS_INTERNAL_ERROR;
306 : }
307 0 : SSVAL(ptr, 0, 0);
308 0 : SSVAL(ptr, 2, 0);
309 0 : return NT_STATUS_OK;
310 : }
311 :
312 626432 : offset = buf->dynamic - buf->hdr;
313 626432 : padding_length = smb2_padding_size(offset, 2);
314 626432 : offset += padding_length;
315 626432 : padding_fix = smb2_padding_fix(buf);
316 :
317 626432 : SSVAL(ptr, 0, offset);
318 626432 : SSVAL(ptr, 2, blob.length);
319 :
320 626432 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
321 626432 : NT_STATUS_NOT_OK_RETURN(status);
322 :
323 626432 : memset(buf->dynamic, 0, padding_length);
324 626432 : buf->dynamic += padding_length;
325 :
326 626432 : memcpy(buf->dynamic, blob.data, blob.length);
327 626432 : buf->dynamic += blob.length;
328 :
329 626432 : buf->size += blob.length + padding_length - padding_fix;
330 626432 : buf->body_size += blob.length + padding_length;
331 :
332 626432 : return NT_STATUS_OK;
333 : }
334 :
335 :
336 : /*
337 : push a uint16_t ofs/ uint32_t length/blob triple into a data blob
338 : the ofs points to the start of the offset/length pair, and is relative
339 : to the body start
340 : */
341 57458 : NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
342 : uint16_t ofs, DATA_BLOB blob)
343 : {
344 2 : NTSTATUS status;
345 2 : size_t offset;
346 2 : size_t padding_length;
347 2 : size_t padding_fix;
348 57458 : uint8_t *ptr = buf->body+ofs;
349 :
350 57458 : if (buf->dynamic == NULL) {
351 0 : return NT_STATUS_INVALID_PARAMETER;
352 : }
353 :
354 : /* check if there're enough room for ofs and size */
355 57458 : if (smb2_oob(buf, ptr, 6)) {
356 0 : return NT_STATUS_INVALID_PARAMETER;
357 : }
358 :
359 57458 : if (blob.data == NULL) {
360 5 : if (blob.length != 0) {
361 0 : return NT_STATUS_INTERNAL_ERROR;
362 : }
363 5 : SSVAL(ptr, 0, 0);
364 5 : SIVAL(ptr, 2, 0);
365 5 : return NT_STATUS_OK;
366 : }
367 :
368 57453 : offset = buf->dynamic - buf->hdr;
369 57453 : padding_length = smb2_padding_size(offset, 2);
370 57453 : offset += padding_length;
371 57453 : padding_fix = smb2_padding_fix(buf);
372 :
373 57453 : SSVAL(ptr, 0, offset);
374 57453 : SIVAL(ptr, 2, blob.length);
375 :
376 57453 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
377 57453 : NT_STATUS_NOT_OK_RETURN(status);
378 :
379 57453 : memset(buf->dynamic, 0, padding_length);
380 57453 : buf->dynamic += padding_length;
381 :
382 57453 : memcpy(buf->dynamic, blob.data, blob.length);
383 57453 : buf->dynamic += blob.length;
384 :
385 57453 : buf->size += blob.length + padding_length - padding_fix;
386 57453 : buf->body_size += blob.length + padding_length;
387 :
388 57453 : return NT_STATUS_OK;
389 : }
390 :
391 :
392 : /*
393 : push a uint32_t ofs/ uint32_t length/blob triple into a data blob
394 : the ofs points to the start of the offset/length pair, and is relative
395 : to the body start
396 : */
397 872904 : NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
398 : uint32_t ofs, DATA_BLOB blob)
399 : {
400 691 : NTSTATUS status;
401 691 : size_t offset;
402 691 : size_t padding_length;
403 691 : size_t padding_fix;
404 872904 : uint8_t *ptr = buf->body+ofs;
405 :
406 872904 : if (buf->dynamic == NULL) {
407 0 : return NT_STATUS_INVALID_PARAMETER;
408 : }
409 :
410 : /* check if there're enough room for ofs and size */
411 872904 : if (smb2_oob(buf, ptr, 8)) {
412 0 : return NT_STATUS_INVALID_PARAMETER;
413 : }
414 :
415 872904 : if (blob.data == NULL) {
416 821340 : if (blob.length != 0) {
417 0 : return NT_STATUS_INTERNAL_ERROR;
418 : }
419 821340 : SIVAL(ptr, 0, 0);
420 821340 : SIVAL(ptr, 4, 0);
421 821340 : return NT_STATUS_OK;
422 : }
423 :
424 51564 : offset = buf->dynamic - buf->hdr;
425 51564 : padding_length = smb2_padding_size(offset, 8);
426 51564 : offset += padding_length;
427 51564 : padding_fix = smb2_padding_fix(buf);
428 :
429 51564 : SIVAL(ptr, 0, offset);
430 51564 : SIVAL(ptr, 4, blob.length);
431 :
432 51564 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
433 51564 : NT_STATUS_NOT_OK_RETURN(status);
434 :
435 51564 : memset(buf->dynamic, 0, padding_length);
436 51564 : buf->dynamic += padding_length;
437 :
438 51564 : memcpy(buf->dynamic, blob.data, blob.length);
439 51564 : buf->dynamic += blob.length;
440 :
441 51564 : buf->size += blob.length + padding_length - padding_fix;
442 51564 : buf->body_size += blob.length + padding_length;
443 :
444 51564 : return NT_STATUS_OK;
445 : }
446 :
447 :
448 : /*
449 : push a uint32_t length/ uint32_t ofs/blob triple into a data blob
450 : the ofs points to the start of the length/offset pair, and is relative
451 : to the body start
452 : */
453 6552 : NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
454 : uint32_t ofs, DATA_BLOB blob)
455 : {
456 4 : NTSTATUS status;
457 4 : size_t offset;
458 4 : size_t padding_length;
459 4 : size_t padding_fix;
460 6552 : uint8_t *ptr = buf->body+ofs;
461 :
462 6552 : if (buf->dynamic == NULL) {
463 0 : return NT_STATUS_INVALID_PARAMETER;
464 : }
465 :
466 : /* check if there're enough room for ofs and size */
467 6552 : if (smb2_oob(buf, ptr, 8)) {
468 0 : return NT_STATUS_INVALID_PARAMETER;
469 : }
470 :
471 6552 : if (blob.data == NULL) {
472 0 : if (blob.length != 0) {
473 0 : return NT_STATUS_INTERNAL_ERROR;
474 : }
475 0 : SIVAL(ptr, 0, 0);
476 0 : SIVAL(ptr, 4, 0);
477 0 : return NT_STATUS_OK;
478 : }
479 :
480 6552 : offset = buf->dynamic - buf->hdr;
481 6552 : padding_length = smb2_padding_size(offset, 8);
482 6552 : offset += padding_length;
483 6552 : padding_fix = smb2_padding_fix(buf);
484 :
485 6552 : SIVAL(ptr, 0, blob.length);
486 6552 : SIVAL(ptr, 4, offset);
487 :
488 6552 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
489 6552 : NT_STATUS_NOT_OK_RETURN(status);
490 :
491 6552 : memset(buf->dynamic, 0, padding_length);
492 6552 : buf->dynamic += padding_length;
493 :
494 6552 : memcpy(buf->dynamic, blob.data, blob.length);
495 6552 : buf->dynamic += blob.length;
496 :
497 6552 : buf->size += blob.length + padding_length - padding_fix;
498 6552 : buf->body_size += blob.length + padding_length;
499 :
500 6552 : return NT_STATUS_OK;
501 : }
502 :
503 : /*
504 : pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
505 : the ptr points to the start of the offset/length pair
506 : */
507 8467 : NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
508 : {
509 2 : uint16_t ofs;
510 2 : uint32_t size;
511 :
512 8467 : if (smb2_oob(buf, ptr, 6)) {
513 0 : return NT_STATUS_INVALID_PARAMETER;
514 : }
515 8467 : ofs = SVAL(ptr, 0);
516 8467 : size = IVAL(ptr, 2);
517 8467 : if (ofs == 0) {
518 1266 : *blob = data_blob(NULL, 0);
519 1266 : return NT_STATUS_OK;
520 : }
521 7201 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
522 0 : return NT_STATUS_INVALID_PARAMETER;
523 : }
524 7201 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
525 7201 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
526 7201 : return NT_STATUS_OK;
527 : }
528 :
529 : /*
530 : pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
531 : the ptr points to the start of the offset/length pair
532 : */
533 761197 : NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
534 : {
535 173 : uint32_t ofs, size;
536 761197 : if (smb2_oob(buf, ptr, 8)) {
537 0 : return NT_STATUS_INVALID_PARAMETER;
538 : }
539 761197 : ofs = IVAL(ptr, 0);
540 761197 : size = IVAL(ptr, 4);
541 761197 : if (ofs == 0) {
542 658636 : *blob = data_blob(NULL, 0);
543 658636 : return NT_STATUS_OK;
544 : }
545 102561 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
546 0 : return NT_STATUS_INVALID_PARAMETER;
547 : }
548 102561 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
549 102561 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
550 102561 : return NT_STATUS_OK;
551 : }
552 :
553 : /*
554 : pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
555 : the ptr points to the start of the offset/length pair
556 :
557 : In this variant the uint16_t is padded by an extra 2 bytes, making
558 : the size aligned on 4 byte boundary
559 : */
560 981 : NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
561 : {
562 0 : uint32_t ofs, size;
563 981 : if (smb2_oob(buf, ptr, 8)) {
564 0 : return NT_STATUS_INVALID_PARAMETER;
565 : }
566 981 : ofs = SVAL(ptr, 0);
567 981 : size = IVAL(ptr, 4);
568 981 : if (ofs == 0) {
569 980 : *blob = data_blob(NULL, 0);
570 980 : return NT_STATUS_OK;
571 : }
572 1 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
573 0 : return NT_STATUS_INVALID_PARAMETER;
574 : }
575 1 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
576 1 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
577 1 : return NT_STATUS_OK;
578 : }
579 :
580 : /*
581 : pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
582 : the ptr points to the start of the offset/length pair
583 : */
584 0 : NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
585 : {
586 0 : uint32_t ofs, size;
587 0 : if (smb2_oob(buf, ptr, 8)) {
588 0 : return NT_STATUS_INVALID_PARAMETER;
589 : }
590 0 : size = IVAL(ptr, 0);
591 0 : ofs = IVAL(ptr, 4);
592 0 : if (ofs == 0) {
593 0 : *blob = data_blob(NULL, 0);
594 0 : return NT_STATUS_OK;
595 : }
596 0 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
597 0 : return NT_STATUS_INVALID_PARAMETER;
598 : }
599 0 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
600 0 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
601 0 : return NT_STATUS_OK;
602 : }
603 :
604 : /*
605 : pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
606 : the ptr points to the start of the offset/length pair
607 : */
608 458 : NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
609 : {
610 0 : uint32_t ofs, size;
611 458 : if (smb2_oob(buf, ptr, 8)) {
612 0 : return NT_STATUS_INVALID_PARAMETER;
613 : }
614 458 : size = IVAL(ptr, 0);
615 458 : ofs = SVAL(ptr, 4);
616 458 : if (ofs == 0) {
617 0 : *blob = data_blob(NULL, 0);
618 0 : return NT_STATUS_OK;
619 : }
620 458 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
621 0 : return NT_STATUS_INVALID_PARAMETER;
622 : }
623 458 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
624 458 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
625 458 : return NT_STATUS_OK;
626 : }
627 :
628 : /*
629 : pull a string in a uint16_t ofs/ uint16_t length/blob format
630 : UTF-16 without termination
631 : */
632 212408 : NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
633 : uint8_t *ptr, const char **str)
634 : {
635 0 : DATA_BLOB blob;
636 0 : NTSTATUS status;
637 0 : void *vstr;
638 212408 : size_t converted_size = 0;
639 0 : bool ret;
640 :
641 212408 : status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
642 212408 : NT_STATUS_NOT_OK_RETURN(status);
643 :
644 212408 : if (blob.data == NULL) {
645 0 : *str = NULL;
646 0 : return NT_STATUS_OK;
647 : }
648 :
649 212408 : if (blob.length == 0) {
650 0 : char *s;
651 5907 : s = talloc_strdup(mem_ctx, "");
652 5907 : NT_STATUS_HAVE_NO_MEMORY(s);
653 5907 : *str = s;
654 5907 : return NT_STATUS_OK;
655 : }
656 :
657 206501 : ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
658 206501 : blob.data, blob.length, &vstr, &converted_size);
659 206501 : data_blob_free(&blob);
660 206501 : (*str) = (char *)vstr;
661 206501 : if (!ret) {
662 0 : return NT_STATUS_ILLEGAL_CHARACTER;
663 : }
664 206501 : return NT_STATUS_OK;
665 : }
666 :
667 : /*
668 : push a string in a uint16_t ofs/ uint16_t length/blob format
669 : UTF-16 without termination
670 : */
671 622634 : NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
672 : uint16_t ofs, const char *str)
673 : {
674 367 : DATA_BLOB blob;
675 367 : NTSTATUS status;
676 367 : bool ret;
677 622634 : void *ptr = NULL;
678 :
679 622634 : if (str == NULL) {
680 0 : return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
681 : }
682 :
683 622634 : if (*str == 0) {
684 31583 : blob.data = discard_const_p(uint8_t, str);
685 31583 : blob.length = 0;
686 31583 : return smb2_push_o16s16_blob(buf, ofs, blob);
687 : }
688 :
689 591051 : ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
690 : str, strlen(str), &ptr, &blob.length);
691 591051 : if (!ret) {
692 0 : return NT_STATUS_ILLEGAL_CHARACTER;
693 : }
694 591051 : blob.data = (uint8_t *)ptr;
695 :
696 591051 : status = smb2_push_o16s16_blob(buf, ofs, blob);
697 591051 : data_blob_free(&blob);
698 591051 : return status;
699 : }
700 :
701 : /*
702 : push a file handle into a buffer
703 : */
704 540637 : void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
705 : {
706 540637 : SBVAL(data, 0, h->data[0]);
707 540637 : SBVAL(data, 8, h->data[1]);
708 540637 : }
709 :
710 : /*
711 : pull a file handle from a buffer
712 : */
713 501396 : void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
714 : {
715 501396 : h->data[0] = BVAL(ptr, 0);
716 501396 : h->data[1] = BVAL(ptr, 8);
717 501396 : }
|