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