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