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