source: vendor/3.6.0/source4/libcli/smb2/request.c

Last change on this file was 740, checked in by Silvan Scherrer, 13 years ago

Samba Server: update vendor to 3.6.0

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