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