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