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

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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