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 355757 : void smb2_setup_bufinfo(struct smb2_request *req)
32 : {
33 355757 : req->in.bufinfo.mem_ctx = req;
34 355757 : req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE | BUFINFO_FLAG_SMB2;
35 355757 : req->in.bufinfo.align_base = req->in.buffer;
36 355757 : if (req->in.dynamic) {
37 355757 : req->in.bufinfo.data = req->in.dynamic;
38 355757 : 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 355757 : }
44 :
45 : /*
46 : initialise a smb2 request
47 : */
48 355769 : 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 355769 : bool compound = false;
55 :
56 355769 : if (body_dynamic_present) {
57 211939 : if (body_dynamic_size == 0) {
58 211572 : body_dynamic_size = 1;
59 : }
60 : } else {
61 143830 : body_dynamic_size = 0;
62 : }
63 :
64 355769 : req = talloc_zero(transport, struct smb2_request);
65 355769 : if (req == NULL) return NULL;
66 :
67 355769 : req->state = SMB2_REQUEST_INIT;
68 355769 : req->transport = transport;
69 :
70 355769 : hdr_offset = NBT_HDR_SIZE;
71 :
72 355769 : req->out.size = hdr_offset + SMB2_HDR_BODY + body_fixed_size;
73 355769 : req->out.allocated = req->out.size + body_dynamic_size;
74 :
75 355769 : req->out.buffer = talloc_realloc(req, req->out.buffer,
76 : uint8_t, req->out.allocated);
77 355769 : if (req->out.buffer == NULL) {
78 0 : talloc_free(req);
79 0 : return NULL;
80 : }
81 :
82 355769 : req->out.hdr = req->out.buffer + hdr_offset;
83 355769 : req->out.body = req->out.hdr + SMB2_HDR_BODY;
84 355769 : req->out.body_fixed= body_fixed_size;
85 355769 : req->out.body_size = body_fixed_size;
86 355769 : req->out.dynamic = (body_dynamic_size ? req->out.body + body_fixed_size : NULL);
87 :
88 355769 : SIVAL(req->out.hdr, 0, SMB2_MAGIC);
89 355769 : SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
90 355769 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT_CHARGE, 0);
91 355769 : SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
92 355769 : SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
93 355769 : SSVAL(req->out.hdr, SMB2_HDR_CREDIT, 0);
94 355769 : SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
95 355769 : SIVAL(req->out.hdr, SMB2_HDR_NEXT_COMMAND, 0);
96 355769 : SBVAL(req->out.hdr, SMB2_HDR_MESSAGE_ID, 0);
97 355769 : SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
98 355769 : SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
99 355769 : SBVAL(req->out.hdr, SMB2_HDR_SESSION_ID, 0);
100 355769 : 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 355769 : 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 355769 : if (body_dynamic_size && !compound) {
110 211939 : req->out.size += 1;
111 211939 : SCVAL(req->out.dynamic, 0, 0);
112 : }
113 :
114 355769 : return req;
115 : }
116 :
117 : /*
118 : initialise a smb2 request for tree operations
119 : */
120 355743 : 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 355743 : struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
125 : body_fixed_size, body_dynamic_present,
126 : body_dynamic_size);
127 355743 : if (req == NULL) return NULL;
128 :
129 355743 : req->session = tree->session;
130 355743 : req->tree = tree;
131 :
132 355743 : return req;
133 : }
134 :
135 : /* destroy a request structure and return final status */
136 355758 : 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 355758 : if (!req) return NT_STATUS_UNSUCCESSFUL;
143 :
144 355760 : if (req->state == SMB2_REQUEST_ERROR &&
145 4 : NT_STATUS_IS_OK(req->status)) {
146 0 : status = NT_STATUS_INTERNAL_ERROR;
147 : } else {
148 355758 : status = req->status;
149 : }
150 :
151 355758 : talloc_free(req);
152 355758 : return status;
153 : }
154 :
155 : /*
156 : receive a response to a packet
157 : */
158 355760 : 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 355760 : if (!req) return false;
163 :
164 : /* keep receiving packets until this one is replied to */
165 1274320 : while (req->state <= SMB2_REQUEST_RECV) {
166 563268 : if (tevent_loop_once(req->transport->ev) != 0) {
167 0 : return false;
168 : }
169 : }
170 :
171 355760 : 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 353860 : bool smb2_request_is_ok(struct smb2_request *req)
182 : {
183 353860 : 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 1900792 : bool smb2_oob(struct smb2_request_buffer *buf, const uint8_t *ptr, size_t size)
190 : {
191 1900792 : if (size == 0) {
192 : /* zero bytes is never out of range */
193 52176 : return false;
194 : }
195 : /* be careful with wraparound! */
196 3627799 : if ((uintptr_t)ptr < (uintptr_t)buf->body ||
197 3627799 : (uintptr_t)ptr >= (uintptr_t)buf->body + buf->body_size ||
198 3627799 : size > buf->body_size ||
199 1848616 : (uintptr_t)ptr + size > (uintptr_t)buf->body + buf->body_size) {
200 0 : return true;
201 : }
202 1848616 : return false;
203 : }
204 :
205 262693 : size_t smb2_padding_size(uint32_t offset, size_t n)
206 : {
207 262693 : if ((offset & (n-1)) == 0) return 0;
208 83 : return n - (offset & (n-1));
209 : }
210 :
211 262693 : static size_t smb2_padding_fix(struct smb2_request_buffer *buf)
212 : {
213 262693 : if (buf->dynamic == (buf->body + buf->body_fixed)) {
214 262583 : if (buf->dynamic != (buf->buffer + buf->size)) {
215 262583 : return 1;
216 : }
217 : }
218 110 : return 0;
219 : }
220 :
221 : /*
222 : grow a SMB2 buffer by the specified amount
223 : */
224 271806 : 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 271806 : uint32_t newsize = buf->size + increase;
230 :
231 : /* a packet size should be limited a bit */
232 271806 : if (newsize >= 0x00FFFFFF) return NT_STATUS_MARSHALL_OVERFLOW;
233 :
234 271806 : 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 213732 : 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 213732 : if (smb2_oob(buf, ptr, 4)) {
259 0 : return NT_STATUS_INVALID_PARAMETER;
260 : }
261 213732 : ofs = SVAL(ptr, 0);
262 213732 : size = SVAL(ptr, 2);
263 213732 : if (ofs == 0) {
264 1 : *blob = data_blob(NULL, 0);
265 1 : return NT_STATUS_OK;
266 : }
267 213731 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
268 0 : return NT_STATUS_INVALID_PARAMETER;
269 : }
270 213731 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
271 213731 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
272 213731 : 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 213686 : 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 213686 : uint8_t *ptr = buf->body+ofs;
288 :
289 213686 : if (buf->dynamic == NULL) {
290 0 : return NT_STATUS_INVALID_PARAMETER;
291 : }
292 :
293 : /* we have only 16 bit for the size */
294 213686 : 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 213686 : if (smb2_oob(buf, ptr, 4)) {
300 0 : return NT_STATUS_INVALID_PARAMETER;
301 : }
302 :
303 213686 : 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 213686 : offset = buf->dynamic - buf->hdr;
313 213686 : padding_length = smb2_padding_size(offset, 2);
314 213686 : offset += padding_length;
315 213686 : padding_fix = smb2_padding_fix(buf);
316 :
317 213686 : SSVAL(ptr, 0, offset);
318 213686 : SSVAL(ptr, 2, blob.length);
319 :
320 213686 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
321 213686 : NT_STATUS_NOT_OK_RETURN(status);
322 :
323 213686 : memset(buf->dynamic, 0, padding_length);
324 213686 : buf->dynamic += padding_length;
325 :
326 213686 : memcpy(buf->dynamic, blob.data, blob.length);
327 213686 : buf->dynamic += blob.length;
328 :
329 213686 : buf->size += blob.length + padding_length - padding_fix;
330 213686 : buf->body_size += blob.length + padding_length;
331 :
332 213686 : 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 2865 : 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 2865 : uint8_t *ptr = buf->body+ofs;
349 :
350 2865 : 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 2865 : if (smb2_oob(buf, ptr, 6)) {
356 0 : return NT_STATUS_INVALID_PARAMETER;
357 : }
358 :
359 2865 : 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 2860 : offset = buf->dynamic - buf->hdr;
369 2860 : padding_length = smb2_padding_size(offset, 2);
370 2860 : offset += padding_length;
371 2860 : padding_fix = smb2_padding_fix(buf);
372 :
373 2860 : SSVAL(ptr, 0, offset);
374 2860 : SIVAL(ptr, 2, blob.length);
375 :
376 2860 : status = smb2_grow_buffer(buf, blob.length + padding_length - padding_fix);
377 2860 : NT_STATUS_NOT_OK_RETURN(status);
378 :
379 2860 : memset(buf->dynamic, 0, padding_length);
380 2860 : buf->dynamic += padding_length;
381 :
382 2860 : memcpy(buf->dynamic, blob.data, blob.length);
383 2860 : buf->dynamic += blob.length;
384 :
385 2860 : buf->size += blob.length + padding_length - padding_fix;
386 2860 : buf->body_size += blob.length + padding_length;
387 :
388 2860 : 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 444187 : 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 444187 : uint8_t *ptr = buf->body+ofs;
405 :
406 444187 : 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 444187 : if (smb2_oob(buf, ptr, 8)) {
412 0 : return NT_STATUS_INVALID_PARAMETER;
413 : }
414 :
415 444187 : if (blob.data == NULL) {
416 398168 : if (blob.length != 0) {
417 0 : return NT_STATUS_INTERNAL_ERROR;
418 : }
419 398168 : SIVAL(ptr, 0, 0);
420 398168 : SIVAL(ptr, 4, 0);
421 398168 : 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 2162 : 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 2162 : if (smb2_oob(buf, ptr, 6)) {
513 0 : return NT_STATUS_INVALID_PARAMETER;
514 : }
515 2162 : ofs = SVAL(ptr, 0);
516 2162 : size = IVAL(ptr, 2);
517 2162 : if (ofs == 0) {
518 127 : *blob = data_blob(NULL, 0);
519 127 : return NT_STATUS_OK;
520 : }
521 2035 : if (smb2_oob(buf, buf->hdr + ofs, size)) {
522 0 : return NT_STATUS_INVALID_PARAMETER;
523 : }
524 2035 : *blob = data_blob_talloc(mem_ctx, buf->hdr + ofs, size);
525 2035 : NT_STATUS_HAVE_NO_MEMORY(blob->data);
526 2035 : 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 446367 : 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 446367 : if (smb2_oob(buf, ptr, 8)) {
537 0 : return NT_STATUS_INVALID_PARAMETER;
538 : }
539 446367 : ofs = IVAL(ptr, 0);
540 446367 : size = IVAL(ptr, 4);
541 446367 : if (ofs == 0) {
542 351302 : *blob = data_blob(NULL, 0);
543 351302 : 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 210910 : 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 210910 : size_t converted_size = 0;
639 : bool ret;
640 :
641 210910 : status = smb2_pull_o16s16_blob(buf, mem_ctx, ptr, &blob);
642 210910 : NT_STATUS_NOT_OK_RETURN(status);
643 :
644 210910 : if (blob.data == NULL) {
645 0 : *str = NULL;
646 0 : return NT_STATUS_OK;
647 : }
648 :
649 210910 : if (blob.length == 0) {
650 : char *s;
651 4684 : s = talloc_strdup(mem_ctx, "");
652 4684 : NT_STATUS_HAVE_NO_MEMORY(s);
653 4684 : *str = s;
654 4684 : 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 210194 : 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 210194 : void *ptr = NULL;
678 :
679 210194 : if (str == NULL) {
680 0 : return smb2_push_o16s16_blob(buf, ofs, data_blob(NULL, 0));
681 : }
682 :
683 210194 : if (*str == 0) {
684 9113 : blob.data = discard_const_p(uint8_t, str);
685 9113 : blob.length = 0;
686 9113 : 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 145828 : void smb2_push_handle(uint8_t *data, struct smb2_handle *h)
705 : {
706 145828 : SBVAL(data, 0, h->data[0]);
707 145828 : SBVAL(data, 8, h->data[1]);
708 145828 : }
709 :
710 : /*
711 : pull a file handle from a buffer
712 : */
713 190584 : void smb2_pull_handle(uint8_t *ptr, struct smb2_handle *h)
714 : {
715 190584 : h->data[0] = BVAL(ptr, 0);
716 190584 : h->data[1] = BVAL(ptr, 8);
717 190584 : }
|