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