updated SMB2 code for getinfo according to WSPP docs
[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         /* be careful with wraparound! */
210         if (ptr < buf->body ||
211             ptr >= buf->body + buf->body_size ||
212             size > buf->body_size ||
213             ptr + size > buf->body + buf->body_size) {
214                 return true;
215         }
216         return false;
217 }
218
219 size_t smb2_padding_size(uint32_t offset, size_t n)
220 {
221         if ((offset & (n-1)) == 0) return 0;
222         return n - (offset & (n-1));
223 }
224
225 static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
226 {
227         if (buf->dynamic == (buf->body + buf->body_fixed)) {
228                 return 1;
229         }
230         return 0;
231 }
232
233 /*
234   grow a SMB2 buffer by the specified amount
235 */
236 static NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
237 {
238         size_t dynamic_ofs;
239         uint8_t *buffer_ptr;
240         uint32_t newsize = buf->size + increase;
241
242         /* a packet size should be limited a bit */
243         if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
244
245         if (newsize <= buf->allocated) return NT_STATUS_OK;
246
247         dynamic_ofs = buf->dynamic - buf->buffer;
248
249         buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
250         NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
251
252         buf->buffer     = buffer_ptr;
253         buf->hdr        = buf->buffer + NBT_HDR_SIZE;
254         buf->body       = buf->hdr    + SMB2_HDR_BODY;
255         buf->dynamic    = buf->buffer + dynamic_ofs;
256         buf->allocated  = newsize;
257
258         return NT_STATUS_OK;
259 }
260
261 /*
262   pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
263   the ptr points to the start of the offset/length pair
264 */
265 NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
266 {
267         uint16_t ofs, size;
268         if (smb2_oob(buf, ptr, 4)) {
269                 return NT_STATUS_BUFFER_TOO_SMALL;
270         }
271         ofs  = SVAL(ptr, 0);
272         size = SVAL(ptr, 2);
273         if (ofs == 0 || size == 0) {
274                 *blob = data_blob(NULL, 0);
275                 return NT_STATUS_OK;
276         }
277         if (smb2_oob(buf, buf->hdr + ofs, size)) {
278                 return NT_STATUS_BUFFER_TOO_SMALL;
279         }
280         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
281         NT_STATUS_HAVE_NO_MEMORY(blob->data);
282         return NT_STATUS_OK;
283 }
284
285 /*
286   push a uint16_t ofs/ uint16_t length/blob triple into a data blob
287   the ofs points to the start of the offset/length pair, and is relative
288   to the body start
289 */
290 NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf, 
291                                uint16_t ofs, DATA_BLOB blob)
292 {
293         NTSTATUS status;
294         size_t offset;
295         size_t padding_length;
296         size_t padding_fix;
297         uint8_t *ptr = buf->body+ofs;
298
299         if (buf->dynamic == NULL) {
300                 return NT_STATUS_INVALID_PARAMETER;
301         }
302
303         /* we have only 16 bit for the size */
304         if (blob.length > 0xFFFF) {
305                 return NT_STATUS_BUFFER_TOO_SMALL;
306         }
307
308         /* check if there're enough room for ofs and size */
309         if (smb2_oob(buf, ptr, 4)) {
310                 return NT_STATUS_BUFFER_TOO_SMALL;
311         }
312
313         if (blob.length == 0) {
314                 SSVAL(ptr, 0, 0);
315                 SSVAL(ptr, 2, 0);
316                 return NT_STATUS_OK;
317         }
318
319         offset = buf->dynamic - buf->hdr;
320         padding_length = smb2_padding_size(offset, 2);
321         offset += padding_length;
322         padding_fix = smb2_padding_fix(buf);
323
324         SSVAL(ptr, 0, offset);
325         SSVAL(ptr, 2, blob.length);
326
327         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
328         NT_STATUS_NOT_OK_RETURN(status);
329
330         memset(buf->dynamic, 0, padding_length);
331         buf->dynamic += padding_length;
332
333         memcpy(buf->dynamic, blob.data, blob.length);
334         buf->dynamic += blob.length;
335
336         buf->size += blob.length + padding_length - padding_fix;
337         buf->body_size += blob.length + padding_length;
338
339         return NT_STATUS_OK;
340 }
341
342
343 /*
344   push a uint16_t ofs/ uint32_t length/blob triple into a data blob
345   the ofs points to the start of the offset/length pair, and is relative
346   to the body start
347 */
348 NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf, 
349                                uint16_t ofs, DATA_BLOB blob)
350 {
351         NTSTATUS status;
352         size_t offset;
353         size_t padding_length;
354         size_t padding_fix;
355         uint8_t *ptr = buf->body+ofs;
356
357         if (buf->dynamic == NULL) {
358                 return NT_STATUS_INVALID_PARAMETER;
359         }
360
361         /* check if there're enough room for ofs and size */
362         if (smb2_oob(buf, ptr, 6)) {
363                 return NT_STATUS_BUFFER_TOO_SMALL;
364         }
365
366         if (blob.length == 0) {
367                 SSVAL(ptr, 0, 0);
368                 SIVAL(ptr, 2, 0);
369                 return NT_STATUS_OK;
370         }
371
372         offset = buf->dynamic - buf->hdr;
373         padding_length = smb2_padding_size(offset, 2);
374         offset += padding_length;
375         padding_fix = smb2_padding_fix(buf);
376
377         SSVAL(ptr, 0, offset);
378         SIVAL(ptr, 2, blob.length);
379
380         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
381         NT_STATUS_NOT_OK_RETURN(status);
382
383         memset(buf->dynamic, 0, padding_length);
384         buf->dynamic += padding_length;
385
386         memcpy(buf->dynamic, blob.data, blob.length);
387         buf->dynamic += blob.length;
388
389         buf->size += blob.length + padding_length - padding_fix;
390         buf->body_size += blob.length + padding_length;
391
392         return NT_STATUS_OK;
393 }
394
395
396 /*
397   push a uint32_t ofs/ uint32_t length/blob triple into a data blob
398   the ofs points to the start of the offset/length pair, and is relative
399   to the body start
400 */
401 NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf, 
402                                uint32_t ofs, DATA_BLOB blob)
403 {
404         NTSTATUS status;
405         size_t offset;
406         size_t padding_length;
407         size_t padding_fix;
408         uint8_t *ptr = buf->body+ofs;
409
410         if (buf->dynamic == NULL) {
411                 return NT_STATUS_INVALID_PARAMETER;
412         }
413
414         /* check if there're enough room for ofs and size */
415         if (smb2_oob(buf, ptr, 8)) {
416                 return NT_STATUS_BUFFER_TOO_SMALL;
417         }
418
419         if (blob.length == 0) {
420                 SIVAL(ptr, 0, 0);
421                 SIVAL(ptr, 4, 0);
422                 return NT_STATUS_OK;
423         }
424
425         offset = buf->dynamic - buf->hdr;
426         padding_length = smb2_padding_size(offset, 8);
427         offset += padding_length;
428         padding_fix = smb2_padding_fix(buf);
429
430         SIVAL(ptr, 0, offset);
431         SIVAL(ptr, 4, blob.length);
432
433         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
434         NT_STATUS_NOT_OK_RETURN(status);
435
436         memset(buf->dynamic, 0, padding_length);
437         buf->dynamic += padding_length;
438
439         memcpy(buf->dynamic, blob.data, blob.length);
440         buf->dynamic += blob.length;
441
442         buf->size += blob.length + padding_length - padding_fix;
443         buf->body_size += blob.length + padding_length;
444
445         return NT_STATUS_OK;
446 }
447
448
449 /*
450   push a uint32_t length/ uint32_t ofs/blob triple into a data blob
451   the ofs points to the start of the length/offset pair, and is relative
452   to the body start
453 */
454 NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf, 
455                                uint32_t ofs, DATA_BLOB blob)
456 {
457         NTSTATUS status;
458         size_t offset;
459         size_t padding_length;
460         size_t padding_fix;
461         uint8_t *ptr = buf->body+ofs;
462
463         if (buf->dynamic == NULL) {
464                 return NT_STATUS_INVALID_PARAMETER;
465         }
466
467         /* check if there're enough room for ofs and size */
468         if (smb2_oob(buf, ptr, 8)) {
469                 return NT_STATUS_BUFFER_TOO_SMALL;
470         }
471
472         if (blob.length == 0) {
473                 SIVAL(ptr, 0, 0);
474                 SIVAL(ptr, 4, 0);
475                 return NT_STATUS_OK;
476         }
477
478         offset = buf->dynamic - buf->hdr;
479         padding_length = smb2_padding_size(offset, 8);
480         offset += padding_length;
481         padding_fix = smb2_padding_fix(buf);
482
483         SIVAL(ptr, 0, blob.length);
484         SIVAL(ptr, 4, offset);
485
486         status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
487         NT_STATUS_NOT_OK_RETURN(status);
488
489         memset(buf->dynamic, 0, padding_length);
490         buf->dynamic += padding_length;
491
492         memcpy(buf->dynamic, blob.data, blob.length);
493         buf->dynamic += blob.length;
494
495         buf->size += blob.length + padding_length - padding_fix;
496         buf->body_size += blob.length + padding_length;
497
498         return NT_STATUS_OK;
499 }
500
501 /*
502   pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
503   the ptr points to the start of the offset/length pair
504 */
505 NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
506 {
507         uint16_t ofs;
508         uint32_t size;
509
510         if (smb2_oob(buf, ptr, 6)) {
511                 return NT_STATUS_BUFFER_TOO_SMALL;
512         }
513         ofs  = SVAL(ptr, 0);
514         size = IVAL(ptr, 2);
515         if (ofs == 0 || size == 0) {
516                 *blob = data_blob(NULL, 0);
517                 return NT_STATUS_OK;
518         }
519         if (smb2_oob(buf, buf->hdr + ofs, size)) {
520                 return NT_STATUS_BUFFER_TOO_SMALL;
521         }
522         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
523         NT_STATUS_HAVE_NO_MEMORY(blob->data);
524         return NT_STATUS_OK;
525 }
526
527 /*
528   pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
529   the ptr points to the start of the offset/length pair
530 */
531 NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
532 {
533         uint32_t ofs, size;
534         if (smb2_oob(buf, ptr, 8)) {
535                 return NT_STATUS_BUFFER_TOO_SMALL;
536         }
537         ofs  = IVAL(ptr, 0);
538         size = IVAL(ptr, 4);
539         if (ofs == 0 || size == 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_BUFFER_TOO_SMALL;
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 uint16_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   In this varient the uint16_t is padded by an extra 2 bytes, making
556   the size aligned on 4 byte boundary
557 */
558 NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
559 {
560         uint32_t ofs, size;
561         if (smb2_oob(buf, ptr, 8)) {
562                 return NT_STATUS_BUFFER_TOO_SMALL;
563         }
564         ofs  = SVAL(ptr, 0);
565         size = IVAL(ptr, 4);
566         if (ofs == 0 || size == 0) {
567                 *blob = data_blob(NULL, 0);
568                 return NT_STATUS_OK;
569         }
570         if (smb2_oob(buf, buf->hdr + ofs, size)) {
571                 return NT_STATUS_BUFFER_TOO_SMALL;
572         }
573         *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
574         NT_STATUS_HAVE_NO_MEMORY(blob->data);
575         return NT_STATUS_OK;
576 }
577
578 /*
579   pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
580   the ptr points to the start of the offset/length pair
581 */
582 NTSTATUS smb2_pull_s32o32_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_BUFFER_TOO_SMALL;
587         }
588         size = IVAL(ptr, 0);
589         ofs  = IVAL(ptr, 4);
590         if (ofs == 0 || size == 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_BUFFER_TOO_SMALL;
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 string in a uint16_t ofs/ uint16_t length/blob format
604   UTF-16 without termination
605 */
606 NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
607                                  uint8_t *ptr, const char **str)
608 {
609         DATA_BLOB blob;
610         NTSTATUS status;
611         ssize_t size;
612         void *vstr;
613
614         status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
615         NT_STATUS_NOT_OK_RETURN(status);
616
617         if (blob.length == 0) {
618                 char *s;
619                 s = talloc_strdup(mem_ctx, "");
620                 NT_STATUS_HAVE_NO_MEMORY(s);
621                 *str = s;
622                 return NT_STATUS_OK;
623         }
624
625         size = convert_string_talloc(mem_ctx, lp_iconv_convenience(global_loadparm), CH_UTF16, CH_UNIX, 
626                                      blob.data, blob.length, &vstr);
627         data_blob_free(&blob);
628         (*str) = (char *)vstr;
629         if (size == -1) {
630                 return NT_STATUS_ILLEGAL_CHARACTER;
631         }
632         return NT_STATUS_OK;
633 }
634
635 /*
636   push a string in a uint16_t ofs/ uint16_t length/blob format
637   UTF-16 without termination
638 */
639 NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
640                                  uint16_t ofs, const char *str)
641 {
642         DATA_BLOB blob;
643         NTSTATUS status;
644         ssize_t size;
645
646         if (strcmp("", str) == 0) {
647                 return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
648         }
649
650         size = convert_string_talloc(buf->buffer, lp_iconv_convenience(global_loadparm), CH_UNIX, CH_UTF16, 
651                                      str, strlen(str), (void **)&blob.data);
652         if (size == -1) {
653                 return NT_STATUS_ILLEGAL_CHARACTER;
654         }
655         blob.length = size;
656
657         status = smb2_push_o16s16_blob(buf, ofs, blob);
658         data_blob_free(&blob);
659         return status;
660 }
661
662 /*
663   push a file handle into a buffer
664 */
665 void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
666 {
667         SBVAL(data, 0, h->data[0]);
668         SBVAL(data, 8, h->data[1]);
669 }
670
671 /*
672   pull a file handle from a buffer
673 */
674 void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
675 {
676         h->data[0] = BVAL(ptr, 0);
677         h->data[1] = BVAL(ptr, 8);
678 }