Line data Source code
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 : #include "libcli/smb2/smb2_calls.h"
29 :
30 : /* fill in the bufinfo */
31 354890 : void smb2_setup_bufinfo(struct smb2_request *req)
32 : {
33 354890 : req->in.bufinfo.mem_ctx = req;
34 354890 : req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
35 354890 : req->in.bufinfo.align_base = req->in.buffer;
36 354890 : if (req->in.dynamic) {
37 354890 : req->in.bufinfo.data = req->in.dynamic;
38 354890 : req->in.bufinfo.data_size = req->in.body_size - req->in.body_fixed;
39 : } else {
40 0 : req->in.bufinfo.data = NULL;
41 0 : req->in.bufinfo.data_size = 0;
42 : }
43 354890 : }
44 :
45 : /*
46 : initialise a smb2 request
47 : */
48 354902 : struct smb2_request *smb2_request_init(struct smb2_transport *transport, uint16_t opcode,
49 : uint16_t body_fixed_size, bool body_dynamic_present,
50 : uint32_t body_dynamic_size)
51 : {
52 : struct smb2_request *req;
53 : uint32_t hdr_offset;
54 354902 : bool compound = false;
55 :
56 354902 : if (body_dynamic_present) {
57 211505 : if (body_dynamic_size == 0) {
58 211138 : body_dynamic_size = 1;
59 : }
60 : } else {
61 143397 : body_dynamic_size = 0;
62 : }
63 :
64 354902 : req = talloc_zero(transport, struct smb2_request);
65 354902 : if (req == NULL) return NULL;
66 :
67 354902 : req->state = SMB2_REQUEST_INIT;
68 354902 : req->transport = transport;
69 :
70 354902 : hdr_offset = NBT_HDR_SIZE;
71 :
72 354902 : req->out.size = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
73 354902 : req->out.allocated = req->out.size + body_dynamic_size;
74 :
75 354902 : req->out.buffer = talloc_realloc(req, req->out.buffer,
76 : uint8_t, req->out.allocated);
77 354902 : if (req->out.buffer == NULL) {
78 0 : talloc_free(req);
79 0 : return NULL;
80 : }
81 :
82 354902 : req->out.hdr = req->out.buffer + hdr_offset;
83 354902 : req->out.body = req->out.hdr + SMB2_HDR_BODY;
84 354902 : req->out.body_fixed= body_fixed_size;
85 354902 : req->out.body_size = body_fixed_size;
86 354902 : req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
87 :
88 354902 : SIVAL(req->out.hdr, 0, SMB2_MAGIC);
89 354902 : SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
90 354902 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE, 0);
91 354902 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
92 354902 : SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
93 354902 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
94 354902 : SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
95 354902 : SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
96 354902 : SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, 0);
97 354902 : SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
98 354902 : SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
99 354902 : SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
100 354902 : memset(req->out.hdr+SMB2_HDR_SIGNATURE, 0, 16);
101 :
102 : /* set the length of the fixed body part and +1 if there's a dynamic part also */
103 354902 : SSVAL(req->out.body, 0, body_fixed_size + (body_dynamic_size?1:0));
104 :
105 : /*
106 : * if we have a dynamic part, make sure the first byte
107 : * which is always be part of the packet is initialized
108 : */
109 354902 : if (body_dynamic_size && !compound) {
110 211505 : req->out.size += 1;
111 211505 : SCVAL(req->out.dynamic, 0, 0);
112 : }
113 :
114 354902 : return req;
115 : }
116 :
117 : /*
118 : initialise a smb2 request for tree operations
119 : */
120 354876 : struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree, uint16_t opcode,
121 : uint16_t body_fixed_size, bool body_dynamic_present,
122 : uint32_t body_dynamic_size)
123 : {
124 354876 : struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
125 : body_fixed_size, body_dynamic_present,
126 : body_dynamic_size);
127 354876 : if (req == NULL) return NULL;
128 :
129 354876 : req->session = tree->session;
130 354876 : req->tree = tree;
131 :
132 354876 : return req;
133 : }
134 :
135 : /* destroy a request structure and return final status */
136 354891 : NTSTATUS smb2_request_destroy(struct smb2_request *req)
137 : {
138 : NTSTATUS status;
139 :
140 : /* this is the error code we give the application for when a
141 : _send() call fails completely */
142 354891 : if (!req) return NT_STATUS_UNSUCCESSFUL;
143 :
144 354893 : if (req->state == SMB2_REQUEST_ERROR &&
145 4 : NT_STATUS_IS_OK(req->status)) {
146 0 : status = NT_STATUS_INTERNAL_ERROR;
147 : } else {
148 354891 : status = req->status;
149 : }
150 :
151 354891 : talloc_free(req);
152 354891 : return status;
153 : }
154 :
155 : /*
156 : receive a response to a packet
157 : */
158 354893 : bool smb2_request_receive(struct smb2_request *req)
159 : {
160 : /* req can be NULL when a send has failed. This eliminates lots of NULL
161 : checks in each module */
162 354893 : if (!req) return false;
163 :
164 : /* keep receiving packets until this one is replied to */
165 1272586 : while (req->state <= SMB2_REQUEST_RECV) {
166 563268 : if (tevent_loop_once(req->transport->ev) != 0) {
167 0 : return false;
168 : }
169 : }
170 :
171 354893 : return req->state == SMB2_REQUEST_DONE;
172 : }
173 :
174 : /* Return true if the last packet was in error */
175 1861 : bool smb2_request_is_error(struct smb2_request *req)
176 : {
177 1861 : return NT_STATUS_IS_ERR(req->status);
178 : }
179 :
180 : /* Return true if the last packet was OK */
181 352993 : bool smb2_request_is_ok(struct smb2_request *req)
182 : {
183 352993 : return NT_STATUS_IS_OK(req->status);
184 : }
185 :
186 : /*
187 : check if a range in the reply body is out of bounds
188 : */
189 1900158 : bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
190 : {
191 1900158 : if (size == 0) {
192 : /* zero bytes is never out of range */
193 52302 : return false;
194 : }
195 : /* be careful with wraparound! */
196 3626283 : if ((uintptr_t)ptr < (uintptr_t)buf->body ||
197 3626283 : (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
198 3626283 : size > buf->body_size ||
199 1847856 : (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
200 0 : return true;
201 : }
202 1847856 : return false;
203 : }
204 :
205 262273 : size_t smb2_padding_size(uint32_t offset, size_t n)
206 : {
207 262273 : if ((offset & (n-1)) == 0) return 0;
208 83 : return n - (offset & (n-1));
209 : }
210 :
211 262273 : static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
212 : {
213 262273 : if (buf->dynamic == (buf->body + buf->body_fixed)) {
214 262163 : if (buf->dynamic != (buf->buffer + buf->size)) {
215 262163 : return 1;
216 : }
217 : }
218 110 : return 0;
219 : }
220 :
221 : /*
222 : grow a SMB2 buffer by the specified amount
223 : */
224 270952 : NTSTATUS smb2_grow_buffer(struct smb2_request_buffer *buf, size_t increase)
225 : {
226 : size_t hdr_ofs;
227 : size_t dynamic_ofs;
228 : uint8_t *buffer_ptr;
229 270952 : uint32_t newsize = buf->size + increase;
230 :
231 : /* a packet size should be limited a bit */
232 270952 : if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
233 :
234 270952 : if (newsize <= buf->allocated) return NT_STATUS_OK;
235 :
236 247086 : hdr_ofs = buf->hdr - buf->buffer;
237 247086 : dynamic_ofs = buf->dynamic - buf->buffer;
238 :
239 247086 : buffer_ptr = talloc_realloc(buf, buf->buffer, uint8_t, newsize);
240 247086 : NT_STATUS_HAVE_NO_MEMORY(buffer_ptr);
241 :
242 247086 : buf->buffer = buffer_ptr;
243 247086 : buf->hdr = buf->buffer + hdr_ofs;
244 247086 : buf->body = buf->hdr + SMB2_HDR_BODY;
245 247086 : buf->dynamic = buf->buffer + dynamic_ofs;
246 247086 : buf->allocated = newsize;
247 :
248 247086 : return NT_STATUS_OK;
249 : }
250 :
251 : /*
252 : pull a uint16_t ofs/ uint16_t length/blob triple from a data blob
253 : the ptr points to the start of the offset/length pair
254 : */
255 213870 : NTSTATUS smb2_pull_o16s16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
256 : {
257 : uint16_t ofs, size;
258 213870 : if (smb2_oob(buf, ptr, 4)) {
259 0 : return NT_STATUS_INVALID_PARAMETER;
260 : }
261 213870 : ofs = SVAL(ptr, 0);
262 213870 : size = SVAL(ptr, 2);
263 213870 : if (ofs == 0) {
264 1 : *blob = data_blob(NULL, 0);
265 1 : return NT_STATUS_OK;
266 : }
267 213869 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
268 0 : return NT_STATUS_INVALID_PARAMETER;
269 : }
270 213869 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
271 213869 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
272 213869 : return NT_STATUS_OK;
273 : }
274 :
275 : /*
276 : push a uint16_t ofs/ uint16_t length/blob triple into a data blob
277 : the ofs points to the start of the offset/length pair, and is relative
278 : to the body start
279 : */
280 213258 : NTSTATUS smb2_push_o16s16_blob(struct smb2_request_buffer *buf,
281 : uint16_t ofs, DATA_BLOB blob)
282 : {
283 : NTSTATUS status;
284 : size_t offset;
285 : size_t padding_length;
286 : size_t padding_fix;
287 213258 : uint8_t *ptr = buf->body+ofs;
288 :
289 213258 : if (buf->dynamic == NULL) {
290 0 : return NT_STATUS_INVALID_PARAMETER;
291 : }
292 :
293 : /* we have only 16 bit for the size */
294 213258 : if (blob.length > 0xFFFF) {
295 0 : return NT_STATUS_INVALID_PARAMETER;
296 : }
297 :
298 : /* check if there're enough room for ofs and size */
299 213258 : if (smb2_oob(buf, ptr, 4)) {
300 0 : return NT_STATUS_INVALID_PARAMETER;
301 : }
302 :
303 213258 : if (blob.data == NULL) {
304 0 : if (blob.length != 0) {
305 0 : return NT_STATUS_INTERNAL_ERROR;
306 : }
307 0 : SSVAL(ptr, 0, 0);
308 0 : SSVAL(ptr, 2, 0);
309 0 : return NT_STATUS_OK;
310 : }
311 :
312 213258 : offset = buf->dynamic - buf->hdr;
313 213258 : padding_length = smb2_padding_size(offset, 2);
314 213258 : offset += padding_length;
315 213258 : padding_fix = smb2_padding_fix(buf);
316 :
317 213258 : SSVAL(ptr, 0, offset);
318 213258 : SSVAL(ptr, 2, blob.length);
319 :
320 213258 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
321 213258 : NT_STATUS_NOT_OK_RETURN(status);
322 :
323 213258 : memset(buf->dynamic, 0, padding_length);
324 213258 : buf->dynamic += padding_length;
325 :
326 213258 : memcpy(buf->dynamic, blob.data, blob.length);
327 213258 : buf->dynamic += blob.length;
328 :
329 213258 : buf->size += blob.length + padding_length - padding_fix;
330 213258 : buf->body_size += blob.length + padding_length;
331 :
332 213258 : return NT_STATUS_OK;
333 : }
334 :
335 :
336 : /*
337 : push a uint16_t ofs/ uint32_t length/blob triple into a data blob
338 : the ofs points to the start of the offset/length pair, and is relative
339 : to the body start
340 : */
341 2873 : NTSTATUS smb2_push_o16s32_blob(struct smb2_request_buffer *buf,
342 : uint16_t ofs, DATA_BLOB blob)
343 : {
344 : NTSTATUS status;
345 : size_t offset;
346 : size_t padding_length;
347 : size_t padding_fix;
348 2873 : uint8_t *ptr = buf->body+ofs;
349 :
350 2873 : if (buf->dynamic == NULL) {
351 0 : return NT_STATUS_INVALID_PARAMETER;
352 : }
353 :
354 : /* check if there're enough room for ofs and size */
355 2873 : if (smb2_oob(buf, ptr, 6)) {
356 0 : return NT_STATUS_INVALID_PARAMETER;
357 : }
358 :
359 2873 : if (blob.data == NULL) {
360 5 : if (blob.length != 0) {
361 0 : return NT_STATUS_INTERNAL_ERROR;
362 : }
363 5 : SSVAL(ptr, 0, 0);
364 5 : SIVAL(ptr, 2, 0);
365 5 : return NT_STATUS_OK;
366 : }
367 :
368 2868 : offset = buf->dynamic - buf->hdr;
369 2868 : padding_length = smb2_padding_size(offset, 2);
370 2868 : offset += padding_length;
371 2868 : padding_fix = smb2_padding_fix(buf);
372 :
373 2868 : SSVAL(ptr, 0, offset);
374 2868 : SIVAL(ptr, 2, blob.length);
375 :
376 2868 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
377 2868 : NT_STATUS_NOT_OK_RETURN(status);
378 :
379 2868 : memset(buf->dynamic, 0, padding_length);
380 2868 : buf->dynamic += padding_length;
381 :
382 2868 : memcpy(buf->dynamic, blob.data, blob.length);
383 2868 : buf->dynamic += blob.length;
384 :
385 2868 : buf->size += blob.length + padding_length - padding_fix;
386 2868 : buf->body_size += blob.length + padding_length;
387 :
388 2868 : return NT_STATUS_OK;
389 : }
390 :
391 :
392 : /*
393 : push a uint32_t ofs/ uint32_t length/blob triple into a data blob
394 : the ofs points to the start of the offset/length pair, and is relative
395 : to the body start
396 : */
397 443879 : NTSTATUS smb2_push_o32s32_blob(struct smb2_request_buffer *buf,
398 : uint32_t ofs, DATA_BLOB blob)
399 : {
400 : NTSTATUS status;
401 : size_t offset;
402 : size_t padding_length;
403 : size_t padding_fix;
404 443879 : uint8_t *ptr = buf->body+ofs;
405 :
406 443879 : if (buf->dynamic == NULL) {
407 0 : return NT_STATUS_INVALID_PARAMETER;
408 : }
409 :
410 : /* check if there're enough room for ofs and size */
411 443879 : if (smb2_oob(buf, ptr, 8)) {
412 0 : return NT_STATUS_INVALID_PARAMETER;
413 : }
414 :
415 443879 : if (blob.data == NULL) {
416 397860 : if (blob.length != 0) {
417 0 : return NT_STATUS_INTERNAL_ERROR;
418 : }
419 397860 : SIVAL(ptr, 0, 0);
420 397860 : SIVAL(ptr, 4, 0);
421 397860 : return NT_STATUS_OK;
422 : }
423 :
424 46019 : offset = buf->dynamic - buf->hdr;
425 46019 : padding_length = smb2_padding_size(offset, 8);
426 46019 : offset += padding_length;
427 46019 : padding_fix = smb2_padding_fix(buf);
428 :
429 46019 : SIVAL(ptr, 0, offset);
430 46019 : SIVAL(ptr, 4, blob.length);
431 :
432 46019 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
433 46019 : NT_STATUS_NOT_OK_RETURN(status);
434 :
435 46019 : memset(buf->dynamic, 0, padding_length);
436 46019 : buf->dynamic += padding_length;
437 :
438 46019 : memcpy(buf->dynamic, blob.data, blob.length);
439 46019 : buf->dynamic += blob.length;
440 :
441 46019 : buf->size += blob.length + padding_length - padding_fix;
442 46019 : buf->body_size += blob.length + padding_length;
443 :
444 46019 : return NT_STATUS_OK;
445 : }
446 :
447 :
448 : /*
449 : push a uint32_t length/ uint32_t ofs/blob triple into a data blob
450 : the ofs points to the start of the length/offset pair, and is relative
451 : to the body start
452 : */
453 128 : NTSTATUS smb2_push_s32o32_blob(struct smb2_request_buffer *buf,
454 : uint32_t ofs, DATA_BLOB blob)
455 : {
456 : NTSTATUS status;
457 : size_t offset;
458 : size_t padding_length;
459 : size_t padding_fix;
460 128 : uint8_t *ptr = buf->body+ofs;
461 :
462 128 : if (buf->dynamic == NULL) {
463 0 : return NT_STATUS_INVALID_PARAMETER;
464 : }
465 :
466 : /* check if there're enough room for ofs and size */
467 128 : if (smb2_oob(buf, ptr, 8)) {
468 0 : return NT_STATUS_INVALID_PARAMETER;
469 : }
470 :
471 128 : if (blob.data == NULL) {
472 0 : if (blob.length != 0) {
473 0 : return NT_STATUS_INTERNAL_ERROR;
474 : }
475 0 : SIVAL(ptr, 0, 0);
476 0 : SIVAL(ptr, 4, 0);
477 0 : return NT_STATUS_OK;
478 : }
479 :
480 128 : offset = buf->dynamic - buf->hdr;
481 128 : padding_length = smb2_padding_size(offset, 8);
482 128 : offset += padding_length;
483 128 : padding_fix = smb2_padding_fix(buf);
484 :
485 128 : SIVAL(ptr, 0, blob.length);
486 128 : SIVAL(ptr, 4, offset);
487 :
488 128 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
489 128 : NT_STATUS_NOT_OK_RETURN(status);
490 :
491 128 : memset(buf->dynamic, 0, padding_length);
492 128 : buf->dynamic += padding_length;
493 :
494 128 : memcpy(buf->dynamic, blob.data, blob.length);
495 128 : buf->dynamic += blob.length;
496 :
497 128 : buf->size += blob.length + padding_length - padding_fix;
498 128 : buf->body_size += blob.length + padding_length;
499 :
500 128 : return NT_STATUS_OK;
501 : }
502 :
503 : /*
504 : pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
505 : the ptr points to the start of the offset/length pair
506 : */
507 2155 : NTSTATUS smb2_pull_o16s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
508 : {
509 : uint16_t ofs;
510 : uint32_t size;
511 :
512 2155 : if (smb2_oob(buf, ptr, 6)) {
513 0 : return NT_STATUS_INVALID_PARAMETER;
514 : }
515 2155 : ofs = SVAL(ptr, 0);
516 2155 : size = IVAL(ptr, 2);
517 2155 : if (ofs == 0) {
518 127 : *blob = data_blob(NULL, 0);
519 127 : return NT_STATUS_OK;
520 : }
521 2028 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
522 0 : return NT_STATUS_INVALID_PARAMETER;
523 : }
524 2028 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
525 2028 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
526 2028 : return NT_STATUS_OK;
527 : }
528 :
529 : /*
530 : pull a uint32_t ofs/ uint32_t length/blob triple from a data blob
531 : the ptr points to the start of the offset/length pair
532 : */
533 446060 : NTSTATUS smb2_pull_o32s32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
534 : {
535 : uint32_t ofs, size;
536 446060 : if (smb2_oob(buf, ptr, 8)) {
537 0 : return NT_STATUS_INVALID_PARAMETER;
538 : }
539 446060 : ofs = IVAL(ptr, 0);
540 446060 : size = IVAL(ptr, 4);
541 446060 : if (ofs == 0) {
542 350995 : *blob = data_blob(NULL, 0);
543 350995 : return NT_STATUS_OK;
544 : }
545 95065 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
546 0 : return NT_STATUS_INVALID_PARAMETER;
547 : }
548 95065 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
549 95065 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
550 95065 : return NT_STATUS_OK;
551 : }
552 :
553 : /*
554 : pull a uint16_t ofs/ uint32_t length/blob triple from a data blob
555 : the ptr points to the start of the offset/length pair
556 :
557 : In this varient the uint16_t is padded by an extra 2 bytes, making
558 : the size aligned on 4 byte boundary
559 : */
560 935 : NTSTATUS smb2_pull_o16As32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
561 : {
562 : uint32_t ofs, size;
563 935 : if (smb2_oob(buf, ptr, 8)) {
564 0 : return NT_STATUS_INVALID_PARAMETER;
565 : }
566 935 : ofs = SVAL(ptr, 0);
567 935 : size = IVAL(ptr, 4);
568 935 : if (ofs == 0) {
569 934 : *blob = data_blob(NULL, 0);
570 934 : return NT_STATUS_OK;
571 : }
572 1 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
573 0 : return NT_STATUS_INVALID_PARAMETER;
574 : }
575 1 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
576 1 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
577 1 : return NT_STATUS_OK;
578 : }
579 :
580 : /*
581 : pull a uint32_t length/ uint32_t ofs/blob triple from a data blob
582 : the ptr points to the start of the offset/length pair
583 : */
584 0 : NTSTATUS smb2_pull_s32o32_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
585 : {
586 : uint32_t ofs, size;
587 0 : if (smb2_oob(buf, ptr, 8)) {
588 0 : return NT_STATUS_INVALID_PARAMETER;
589 : }
590 0 : size = IVAL(ptr, 0);
591 0 : ofs = IVAL(ptr, 4);
592 0 : if (ofs == 0) {
593 0 : *blob = data_blob(NULL, 0);
594 0 : return NT_STATUS_OK;
595 : }
596 0 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
597 0 : return NT_STATUS_INVALID_PARAMETER;
598 : }
599 0 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
600 0 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
601 0 : return NT_STATUS_OK;
602 : }
603 :
604 : /*
605 : pull a uint32_t length/ uint16_t ofs/blob triple from a data blob
606 : the ptr points to the start of the offset/length pair
607 : */
608 413 : NTSTATUS smb2_pull_s32o16_blob(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx, uint8_t *ptr, DATA_BLOB *blob)
609 : {
610 : uint32_t ofs, size;
611 413 : if (smb2_oob(buf, ptr, 8)) {
612 0 : return NT_STATUS_INVALID_PARAMETER;
613 : }
614 413 : size = IVAL(ptr, 0);
615 413 : ofs = SVAL(ptr, 4);
616 413 : if (ofs == 0) {
617 0 : *blob = data_blob(NULL, 0);
618 0 : return NT_STATUS_OK;
619 : }
620 413 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
621 0 : return NT_STATUS_INVALID_PARAMETER;
622 : }
623 413 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
624 413 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
625 413 : return NT_STATUS_OK;
626 : }
627 :
628 : /*
629 : pull a string in a uint16_t ofs/ uint16_t length/blob format
630 : UTF-16 without termination
631 : */
632 211036 : NTSTATUS smb2_pull_o16s16_string(struct smb2_request_buffer *buf, TALLOC_CTX *mem_ctx,
633 : uint8_t *ptr, const char **str)
634 : {
635 : DATA_BLOB blob;
636 : NTSTATUS status;
637 : void *vstr;
638 211036 : size_t converted_size = 0;
639 : bool ret;
640 :
641 211036 : status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
642 211036 : NT_STATUS_NOT_OK_RETURN(status);
643 :
644 211036 : if (blob.data == NULL) {
645 0 : *str = NULL;
646 0 : return NT_STATUS_OK;
647 : }
648 :
649 211036 : if (blob.length == 0) {
650 : char *s;
651 4810 : s = talloc_strdup(mem_ctx, "");
652 4810 : NT_STATUS_HAVE_NO_MEMORY(s);
653 4810 : *str = s;
654 4810 : return NT_STATUS_OK;
655 : }
656 :
657 411685 : ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX,
658 206226 : blob.data, blob.length, &vstr, &converted_size);
659 206226 : data_blob_free(&blob);
660 206226 : (*str) = (char *)vstr;
661 206226 : if (!ret) {
662 0 : return NT_STATUS_ILLEGAL_CHARACTER;
663 : }
664 206226 : return NT_STATUS_OK;
665 : }
666 :
667 : /*
668 : push a string in a uint16_t ofs/ uint16_t length/blob format
669 : UTF-16 without termination
670 : */
671 209760 : NTSTATUS smb2_push_o16s16_string(struct smb2_request_buffer *buf,
672 : uint16_t ofs, const char *str)
673 : {
674 : DATA_BLOB blob;
675 : NTSTATUS status;
676 : bool ret;
677 209760 : void *ptr = NULL;
678 :
679 209760 : if (str == NULL) {
680 0 : return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
681 : }
682 :
683 209760 : if (*str == 0) {
684 8679 : blob.data = discard_const_p(uint8_t, str);
685 8679 : blob.length = 0;
686 8679 : return smb2_push_o16s16_blob(buf, ofs, blob);
687 : }
688 :
689 201081 : ret = convert_string_talloc(buf->buffer, CH_UNIX, CH_UTF16,
690 : str, strlen(str), &ptr, &blob.length);
691 201081 : if (!ret) {
692 0 : return NT_STATUS_ILLEGAL_CHARACTER;
693 : }
694 201081 : blob.data = (uint8_t *)ptr;
695 :
696 201081 : status = smb2_push_o16s16_blob(buf, ofs, blob);
697 201081 : data_blob_free(&blob);
698 201081 : return status;
699 : }
700 :
701 : /*
702 : push a file handle into a buffer
703 : */
704 145395 : void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
705 : {
706 145395 : SBVAL(data, 0, h->data[0]);
707 145395 : SBVAL(data, 8, h->data[1]);
708 145395 : }
709 :
710 : /*
711 : pull a file handle from a buffer
712 : */
713 190151 : void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
714 : {
715 190151 : h->data[0] = BVAL(ptr, 0);
716 190151 : h->data[1] = BVAL(ptr, 8);
717 190151 : }
|