19a2862d68c10deb727d41df05843e117afcd417
[nivanova/samba-autobuild/.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
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,
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)
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)
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)
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)
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)
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)
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)
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)
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)
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, 
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, 
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, 
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, 
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)
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)
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)
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)
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)
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,
655                                  uint8_t *ptr, const char **str)
656 {
657         DATA_BLOB blob;
658         NTSTATUS status;
659         ssize_t size;
660         void *vstr;
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         size = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, 
679                                      blob.data, blob.length, &vstr, false);
680         data_blob_free(&blob);
681         (*str) = (char *)vstr;
682         if (size == -1) {
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,
693                                  uint16_t ofs, const char *str)
694 {
695         DATA_BLOB blob;
696         NTSTATUS status;
697         ssize_t size;
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         size = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16, 
710                                      str, strlen(str), (void **)&blob.data, false);
711         if (size == -1) {
712                 return NT_STATUS_ILLEGAL_CHARACTER;
713         }
714         blob.length = size;
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)
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)
734 {
735         h->data[0] = BVAL(ptr, 0);
736         h->data[1] = BVAL(ptr, 8);
737 }