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