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