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