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