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