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