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