source: vendor/current/source4/libcli/raw/rawrequest.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 27.2 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21/*
22 this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb
23*/
24
25#include "includes.h"
26#include "libcli/raw/libcliraw.h"
27#include "libcli/raw/raw_proto.h"
28#include "lib/events/events.h"
29#include "librpc/ndr/libndr.h"
30#include "librpc/gen_ndr/ndr_misc.h"
31#include "../libcli/smb/smbXcli_base.h"
32
33/* we over allocate the data buffer to prevent too many realloc calls */
34#define REQ_OVER_ALLOCATION 0
35
36/* assume that a character will not consume more than 3 bytes per char */
37#define MAX_BYTES_PER_CHAR 3
38
39/* setup the bufinfo used for strings and range checking */
40void smb_setup_bufinfo(struct smbcli_request *req)
41{
42 req->in.bufinfo.mem_ctx = req;
43 req->in.bufinfo.flags = 0;
44 if (req->flags2 & FLAGS2_UNICODE_STRINGS) {
45 req->in.bufinfo.flags = BUFINFO_FLAG_UNICODE;
46 }
47 req->in.bufinfo.align_base = req->in.buffer;
48 req->in.bufinfo.data = req->in.data;
49 req->in.bufinfo.data_size = req->in.data_size;
50}
51
52
53/* destroy a request structure and return final status */
54_PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
55{
56 NTSTATUS status;
57
58 /* this is the error code we give the application for when a
59 _send() call fails completely */
60 if (!req) return NT_STATUS_UNSUCCESSFUL;
61
62 if (req->state == SMBCLI_REQUEST_ERROR &&
63 NT_STATUS_IS_OK(req->status)) {
64 req->status = NT_STATUS_INTERNAL_ERROR;
65 }
66
67 status = req->status;
68
69 if (!req->do_not_free) {
70 talloc_free(req);
71 }
72
73 return status;
74}
75
76
77/*
78 setup a SMB packet at transport level
79*/
80struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
81 uint8_t command, unsigned int wct, unsigned int buflen)
82{
83 struct smbcli_request *req;
84 size_t size;
85
86 size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
87
88 req = talloc_zero(transport, struct smbcli_request);
89 if (!req) {
90 return NULL;
91 }
92
93 /* setup the request context */
94 req->state = SMBCLI_REQUEST_INIT;
95 req->transport = transport;
96 req->out.size = size;
97
98 /* over allocate by a small amount */
99 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
100
101 req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
102 if (!req->out.buffer) {
103 return NULL;
104 }
105
106 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
107 req->out.vwv = req->out.hdr + HDR_VWV;
108 req->out.wct = wct;
109 req->out.data = req->out.vwv + VWV(wct) + 2;
110 req->out.data_size = buflen;
111 req->out.ptr = req->out.data;
112
113 SCVAL(req->out.hdr, HDR_WCT, wct);
114 SSVAL(req->out.vwv, VWV(wct), buflen);
115
116 memcpy(req->out.hdr, "\377SMB", 4);
117 SCVAL(req->out.hdr,HDR_COM,command);
118
119 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
120 SSVAL(req->out.hdr,HDR_FLG2, 0);
121
122 /* copy the pid, uid and mid to the request */
123 SSVAL(req->out.hdr, HDR_PID, 0);
124 SSVAL(req->out.hdr, HDR_UID, 0);
125 SSVAL(req->out.hdr, HDR_MID, 0);
126 SSVAL(req->out.hdr, HDR_TID,0);
127 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
128 SIVAL(req->out.hdr, HDR_RCLS, 0);
129 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
130
131 return req;
132}
133
134/*
135 setup a reply in req->out with the given word count and initial data
136 buffer size. the caller will then fill in the command words and
137 data before calling smbcli_request_send() to send the reply on its
138 way. This interface is used before a session is setup.
139*/
140struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
141 uint8_t command, unsigned int wct, size_t buflen)
142{
143 struct smbcli_request *req;
144
145 req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
146
147 if (!req) return NULL;
148
149 smb1cli_session_set_id(session->smbXcli, session->vuid);
150
151 req->session = session;
152
153 SSVAL(req->out.hdr, HDR_FLG2, session->flags2);
154 SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
155 SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
156 SSVAL(req->out.hdr, HDR_UID, session->vuid);
157
158 return req;
159}
160
161/*
162 setup a request for tree based commands
163*/
164struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
165 uint8_t command,
166 unsigned int wct, unsigned int buflen)
167{
168 struct smbcli_request *req;
169
170 req = smbcli_request_setup_session(tree->session, command, wct, buflen);
171 if (req) {
172 smb1cli_tcon_set_id(tree->smbXcli, tree->tid);
173
174 req->tree = tree;
175 SSVAL(req->out.hdr,HDR_TID,tree->tid);
176 }
177 return req;
178}
179
180
181/*
182 grow the allocation of the data buffer portion of a reply
183 packet. Note that as this can reallocate the packet buffer this
184 invalidates any local pointers into the packet.
185
186 To cope with this req->out.ptr is supplied. This will be updated to
187 point at the same offset into the packet as before this call
188*/
189static void smbcli_req_grow_allocation(struct smbcli_request *req, unsigned int new_size)
190{
191 int delta;
192 uint8_t *buf2;
193
194 delta = new_size - req->out.data_size;
195 if (delta + req->out.size <= req->out.allocated) {
196 /* it fits in the preallocation */
197 return;
198 }
199
200 /* we need to realloc */
201 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
202 buf2 = talloc_realloc(req, req->out.buffer, uint8_t, req->out.allocated);
203 if (buf2 == NULL) {
204 smb_panic("out of memory in req_grow_allocation");
205 }
206
207 if (buf2 == req->out.buffer) {
208 /* the malloc library gave us the same pointer */
209 return;
210 }
211
212 /* update the pointers into the packet */
213 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
214 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
215 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
216 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
217
218 req->out.buffer = buf2;
219}
220
221
222/*
223 grow the data buffer portion of a reply packet. Note that as this
224 can reallocate the packet buffer this invalidates any local pointers
225 into the packet.
226
227 To cope with this req->out.ptr is supplied. This will be updated to
228 point at the same offset into the packet as before this call
229*/
230static void smbcli_req_grow_data(struct smbcli_request *req, unsigned int new_size)
231{
232 int delta;
233
234 smbcli_req_grow_allocation(req, new_size);
235
236 delta = new_size - req->out.data_size;
237
238 req->out.size += delta;
239 req->out.data_size += delta;
240
241 /* set the BCC to the new data size */
242 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
243}
244
245
246/*
247 setup a chained reply in req->out with the given word count and
248 initial data buffer size.
249*/
250NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
251 uint8_t command,
252 unsigned int wct, size_t buflen)
253{
254 size_t wct_ofs;
255 size_t size;
256
257 /*
258 * here we only support one chained command
259 * If someone needs longer chains, the low
260 * level code should be used directly.
261 */
262 if (req->subreqs[0] != NULL) {
263 return NT_STATUS_INVALID_PARAMETER_MIX;
264 }
265 if (req->subreqs[1] != NULL) {
266 return NT_STATUS_INVALID_PARAMETER_MIX;
267 }
268
269 req->subreqs[0] = smbcli_transport_setup_subreq(req);
270 if (req->subreqs[0] == NULL) {
271 return NT_STATUS_NO_MEMORY;
272 }
273
274 wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1);
275
276 size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen;
277
278 req->out.size = size;
279
280 /* over allocate by a small amount */
281 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
282
283 req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
284 if (!req->out.buffer) {
285 return NT_STATUS_NO_MEMORY;
286 }
287
288 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
289 req->out.vwv = req->out.hdr + wct_ofs;
290 req->out.wct = wct;
291 req->out.data = req->out.vwv + VWV(wct) + 2;
292 req->out.data_size = buflen;
293 req->out.ptr = req->out.data;
294
295 SCVAL(req->out.hdr, HDR_WCT, wct);
296 SSVAL(req->out.vwv, VWV(wct), buflen);
297
298 memcpy(req->out.hdr, "\377SMB", 4);
299 SCVAL(req->out.hdr,HDR_COM,command);
300
301 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
302 SSVAL(req->out.hdr,HDR_FLG2, 0);
303
304 /* copy the pid, uid and mid to the request */
305 SSVAL(req->out.hdr, HDR_PID, 0);
306 SSVAL(req->out.hdr, HDR_UID, 0);
307 SSVAL(req->out.hdr, HDR_MID, 0);
308 SSVAL(req->out.hdr, HDR_TID,0);
309 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
310 SIVAL(req->out.hdr, HDR_RCLS, 0);
311 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
312
313 if (req->session != NULL) {
314 SSVAL(req->out.hdr, HDR_FLG2, req->session->flags2);
315 SSVAL(req->out.hdr, HDR_PID, req->session->pid & 0xFFFF);
316 SSVAL(req->out.hdr, HDR_PIDHIGH, req->session->pid >> 16);
317 SSVAL(req->out.hdr, HDR_UID, req->session->vuid);
318 }
319
320 if (req->tree != NULL) {
321 SSVAL(req->out.hdr, HDR_TID, req->tree->tid);
322 }
323
324 return NT_STATUS_OK;
325}
326
327/*
328 advance to the next chained reply in a request
329*/
330NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
331{
332 struct smbcli_transport *transport = req->transport;
333 uint8_t *hdr = NULL;
334 uint8_t wct = 0;
335 uint16_t *vwv = NULL;
336 uint32_t num_bytes = 0;
337 uint8_t *bytes = NULL;
338 struct iovec *recv_iov = NULL;
339 uint8_t *inbuf = NULL;
340
341 if (req->subreqs[0] != NULL) {
342 return NT_STATUS_INVALID_PARAMETER_MIX;
343 }
344 if (req->subreqs[1] == NULL) {
345 return NT_STATUS_INVALID_PARAMETER_MIX;
346 }
347
348 req->status = smb1cli_req_recv(req->subreqs[1], req,
349 &recv_iov,
350 &hdr,
351 &wct,
352 &vwv,
353 NULL, /* pvwv_offset */
354 &num_bytes,
355 &bytes,
356 NULL, /* pbytes_offset */
357 &inbuf,
358 NULL, 0); /* expected */
359 TALLOC_FREE(req->subreqs[1]);
360 if (!NT_STATUS_IS_OK(req->status)) {
361 if (recv_iov == NULL) {
362 req->state = SMBCLI_REQUEST_ERROR;
363 return req->status;
364 }
365 }
366
367 /* fill in the 'in' portion of the matching request */
368 req->in.buffer = inbuf;
369 req->in.size = NBT_HDR_SIZE + PTR_DIFF(bytes, hdr) + num_bytes;
370 req->in.allocated = req->in.size;
371
372 req->in.hdr = hdr;
373 req->in.vwv = (uint8_t *)vwv;
374 req->in.wct = wct;
375 req->in.data = bytes;
376 req->in.data_size = num_bytes;
377 req->in.ptr = req->in.data;
378 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
379
380 smb_setup_bufinfo(req);
381
382 transport->error.e.nt_status = req->status;
383 if (NT_STATUS_IS_OK(req->status)) {
384 transport->error.etype = ETYPE_NONE;
385 } else {
386 transport->error.etype = ETYPE_SMB;
387 }
388
389 req->state = SMBCLI_REQUEST_DONE;
390
391 return NT_STATUS_OK;
392}
393
394
395/*
396 send a message
397*/
398bool smbcli_request_send(struct smbcli_request *req)
399{
400 smbcli_transport_send(req);
401 return true;
402}
403
404
405/*
406 receive a response to a packet
407*/
408bool smbcli_request_receive(struct smbcli_request *req)
409{
410 /* req can be NULL when a send has failed. This eliminates lots of NULL
411 checks in each module */
412 if (!req) return false;
413
414 /* keep receiving packets until this one is replied to */
415 while (req->state <= SMBCLI_REQUEST_RECV) {
416 if (tevent_loop_once(req->transport->ev) != 0) {
417 return false;
418 }
419 }
420
421 return req->state == SMBCLI_REQUEST_DONE;
422}
423
424/*
425 wait for a reply to be received for a packet that just returns an error
426 code and nothing more
427*/
428_PUBLIC_ NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
429{
430 (void) smbcli_request_receive(req);
431 return smbcli_request_destroy(req);
432}
433
434
435/* Return true if the last packet was in error */
436bool smbcli_request_is_error(struct smbcli_request *req)
437{
438 return NT_STATUS_IS_ERR(req->status);
439}
440
441/*
442 append a string into the data portion of the request packet
443
444 return the number of bytes added to the packet
445*/
446size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, unsigned int flags)
447{
448 size_t len;
449
450 /* determine string type to use */
451 if (!(flags & (STR_ASCII|STR_UNICODE))) {
452 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
453 }
454
455 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
456
457 smbcli_req_grow_allocation(req, len + req->out.data_size);
458
459 len = push_string(req->out.data + req->out.data_size, str, len, flags);
460
461 smbcli_req_grow_data(req, len + req->out.data_size);
462
463 return len;
464}
465
466
467/*
468 this is like smbcli_req_append_string but it also return the
469 non-terminated string byte length, which can be less than the number
470 of bytes consumed in the packet for 2 reasons:
471
472 1) the string in the packet may be null terminated
473 2) the string in the packet may need a 1 byte UCS2 alignment
474
475 this is used in places where the non-terminated string byte length is
476 placed in the packet as a separate field
477*/
478size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len)
479{
480 int diff = 0;
481 size_t ret;
482
483 /* determine string type to use */
484 if (!(flags & (STR_ASCII|STR_UNICODE))) {
485 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
486 }
487
488 /* see if an alignment byte will be used */
489 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
490 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
491 }
492
493 /* do the hard work */
494 ret = smbcli_req_append_string(req, str, flags);
495
496 /* see if we need to subtract the termination */
497 if (flags & STR_TERMINATE) {
498 diff += (flags & STR_UNICODE) ? 2 : 1;
499 }
500
501 if (ret >= diff) {
502 (*len) = ret - diff;
503 } else {
504 (*len) = ret;
505 }
506
507 return ret;
508}
509
510
511/*
512 push a string into the data portion of the request packet, growing it if necessary
513 this gets quite tricky - please be very careful to cover all cases when modifying this
514
515 if dest is NULL, then put the string at the end of the data portion of the packet
516
517 if dest_len is -1 then no limit applies
518*/
519size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, unsigned int flags)
520{
521 size_t size;
522 smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
523 size = smbcli_req_append_string(req, str, flags);
524 return size + 1;
525}
526
527
528/*
529 push a blob into the data portion of the request packet, growing it if necessary
530 this gets quite tricky - please be very careful to cover all cases when modifying this
531
532 if dest is NULL, then put the blob at the end of the data portion of the packet
533*/
534size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
535{
536 smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
537 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
538 smbcli_req_grow_data(req, req->out.data_size + blob->length);
539 return blob->length;
540}
541
542/*
543 append raw bytes into the data portion of the request packet
544 return the number of bytes added
545*/
546size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
547{
548 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
549 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
550 smbcli_req_grow_data(req, byte_len + req->out.data_size);
551 return byte_len;
552}
553
554/*
555 append variable block (type 5 buffer) into the data portion of the request packet
556 return the number of bytes added
557*/
558size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
559{
560 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
561 SCVAL(req->out.data + req->out.data_size, 0, 5);
562 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
563 if (byte_len > 0) {
564 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
565 }
566 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
567 return byte_len + 3;
568}
569
570
571/*
572 pull a UCS2 string from a request packet, returning a talloced unix string
573
574 the string length is limited by the 3 things:
575 - the data size in the request (end of packet)
576 - the passed 'byte_len' if it is not -1
577 - the end of string (null termination)
578
579 Note that 'byte_len' is the number of bytes in the packet
580
581 on failure zero is returned and *dest is set to NULL, otherwise the number
582 of bytes consumed in the packet is returned
583*/
584static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
585 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
586{
587 int src_len, src_len2, alignment=0;
588 bool ret;
589 size_t ret_size;
590
591 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
592 src++;
593 alignment=1;
594 if (byte_len != -1) {
595 byte_len--;
596 }
597 }
598
599 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
600 if (src_len < 0) {
601 *dest = NULL;
602 return 0;
603 }
604 if (byte_len != -1 && src_len > byte_len) {
605 src_len = byte_len;
606 }
607
608 src_len2 = utf16_len_n(src, src_len);
609
610 /* ucs2 strings must be at least 2 bytes long */
611 if (src_len2 < 2) {
612 *dest = NULL;
613 return 0;
614 }
615
616 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
617 if (!ret) {
618 *dest = NULL;
619 return 0;
620 }
621
622 return src_len2 + alignment;
623}
624
625/*
626 pull a ascii string from a request packet, returning a talloced string
627
628 the string length is limited by the 3 things:
629 - the data size in the request (end of packet)
630 - the passed 'byte_len' if it is not -1
631 - the end of string (null termination)
632
633 Note that 'byte_len' is the number of bytes in the packet
634
635 on failure zero is returned and *dest is set to NULL, otherwise the number
636 of bytes consumed in the packet is returned
637*/
638size_t smbcli_req_pull_ascii(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
639 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
640{
641 int src_len, src_len2;
642 bool ret;
643 size_t ret_size;
644
645 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
646 if (src_len < 0) {
647 *dest = NULL;
648 return 0;
649 }
650 if (byte_len != -1 && src_len > byte_len) {
651 src_len = byte_len;
652 }
653 src_len2 = strnlen((const char *)src, src_len);
654 if (src_len2 < src_len - 1) {
655 /* include the termination if we didn't reach the end of the packet */
656 src_len2++;
657 }
658
659 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
660
661 if (!ret) {
662 *dest = NULL;
663 return 0;
664 }
665
666 return ret_size;
667}
668
669/**
670 pull a string from a request packet, returning a talloced string
671
672 the string length is limited by the 3 things:
673 - the data size in the request (end of packet)
674 - the passed 'byte_len' if it is not -1
675 - the end of string (null termination)
676
677 Note that 'byte_len' is the number of bytes in the packet
678
679 on failure zero is returned and *dest is set to NULL, otherwise the number
680 of bytes consumed in the packet is returned
681*/
682size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
683 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
684{
685 if (!(flags & STR_ASCII) &&
686 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
687 return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags);
688 }
689
690 return smbcli_req_pull_ascii(bufinfo, mem_ctx, dest, src, byte_len, flags);
691}
692
693
694/**
695 pull a DATA_BLOB from a reply packet, returning a talloced blob
696 make sure we don't go past end of packet
697
698 if byte_len is -1 then limit the blob only by packet size
699*/
700DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
701{
702 int src_len;
703
704 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
705
706 if (src_len < 0) {
707 return data_blob(NULL, 0);
708 }
709
710 if (byte_len != -1 && src_len > byte_len) {
711 src_len = byte_len;
712 }
713
714 return data_blob_talloc(mem_ctx, src, src_len);
715}
716
717/* check that a lump of data in a request is within the bounds of the data section of
718 the packet */
719static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
720{
721 /* be careful with wraparound! */
722 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
723 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
724 count > bufinfo->data_size ||
725 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
726 return true;
727 }
728 return false;
729}
730
731/*
732 pull a lump of data from a request packet
733
734 return false if any part is outside the data portion of the packet
735*/
736bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest)
737{
738 if (len == 0) return true;
739
740 if (smbcli_req_data_oob(bufinfo, src, len)) {
741 return false;
742 }
743
744 memcpy(dest, src, len);
745 return true;
746}
747
748
749/*
750 put a NTTIME into a packet
751*/
752void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
753{
754 SBVAL(base, offset, t);
755}
756
757/*
758 pull a NTTIME from a packet
759*/
760NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
761{
762 NTTIME ret = BVAL(base, offset);
763 return ret;
764}
765
766/**
767 pull a UCS2 string from a blob, returning a talloced unix string
768
769 the string length is limited by the 3 things:
770 - the data size in the blob
771 - the passed 'byte_len' if it is not -1
772 - the end of string (null termination)
773
774 Note that 'byte_len' is the number of bytes in the packet
775
776 on failure zero is returned and *dest is set to NULL, otherwise the number
777 of bytes consumed in the blob is returned
778*/
779size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
780 const DATA_BLOB *blob, const char **dest,
781 const uint8_t *src, int byte_len, unsigned int flags)
782{
783 int src_len, src_len2, alignment=0;
784 size_t ret_size;
785 bool ret;
786 char *dest2;
787
788 if (src < blob->data ||
789 src >= (blob->data + blob->length)) {
790 *dest = NULL;
791 return 0;
792 }
793
794 src_len = blob->length - PTR_DIFF(src, blob->data);
795
796 if (byte_len != -1 && src_len > byte_len) {
797 src_len = byte_len;
798 }
799
800 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
801 src++;
802 alignment=1;
803 src_len--;
804 }
805
806 if (src_len < 2) {
807 *dest = NULL;
808 return 0;
809 }
810
811 src_len2 = utf16_len_n(src, src_len);
812
813 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
814 if (!ret) {
815 *dest = NULL;
816 return 0;
817 }
818 *dest = dest2;
819
820 return src_len2 + alignment;
821}
822
823/**
824 pull a ascii string from a blob, returning a talloced string
825
826 the string length is limited by the 3 things:
827 - the data size in the blob
828 - the passed 'byte_len' if it is not -1
829 - the end of string (null termination)
830
831 Note that 'byte_len' is the number of bytes in the blob
832
833 on failure zero is returned and *dest is set to NULL, otherwise the number
834 of bytes consumed in the blob is returned
835*/
836static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
837 const DATA_BLOB *blob, const char **dest,
838 const uint8_t *src, int byte_len, unsigned int flags)
839{
840 int src_len, src_len2;
841 size_t ret_size;
842 bool ret;
843 char *dest2;
844
845 src_len = blob->length - PTR_DIFF(src, blob->data);
846 if (src_len < 0) {
847 *dest = NULL;
848 return 0;
849 }
850 if (byte_len != -1 && src_len > byte_len) {
851 src_len = byte_len;
852 }
853 src_len2 = strnlen((const char *)src, src_len);
854
855 if (src_len2 < src_len - 1) {
856 /* include the termination if we didn't reach the end of the packet */
857 src_len2++;
858 }
859
860 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
861
862 if (!ret) {
863 *dest = NULL;
864 return 0;
865 }
866 *dest = dest2;
867
868 return ret_size;
869}
870
871/**
872 pull a string from a blob, returning a talloced struct smb_wire_string
873
874 the string length is limited by the 3 things:
875 - the data size in the blob
876 - length field on the wire
877 - the end of string (null termination)
878
879 if STR_LEN8BIT is set in the flags then assume the length field is
880 8 bits, instead of 32
881
882 on failure zero is returned and dest->s is set to NULL, otherwise the number
883 of bytes consumed in the blob is returned
884*/
885size_t smbcli_blob_pull_string(struct smbcli_session *session,
886 TALLOC_CTX *mem_ctx,
887 const DATA_BLOB *blob,
888 struct smb_wire_string *dest,
889 uint16_t len_offset, uint16_t str_offset,
890 unsigned int flags)
891{
892 int extra;
893 dest->s = NULL;
894
895 if (!(flags & STR_ASCII)) {
896 /* this is here to cope with SMB2 calls using the SMB
897 parsers. SMB2 will pass smbcli_session==NULL, which forces
898 unicode on (as used by SMB2) */
899 if (session == NULL) {
900 flags |= STR_UNICODE;
901 } else if (session->transport->negotiate.capabilities & CAP_UNICODE) {
902 flags |= STR_UNICODE;
903 }
904 }
905
906 if (flags & STR_LEN8BIT) {
907 if (len_offset > blob->length-1) {
908 return 0;
909 }
910 dest->private_length = CVAL(blob->data, len_offset);
911 } else {
912 if (len_offset > blob->length-4) {
913 return 0;
914 }
915 dest->private_length = IVAL(blob->data, len_offset);
916 }
917 extra = 0;
918 dest->s = NULL;
919 if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
920 int align = 0;
921 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
922 align = 1;
923 }
924 if (flags & STR_LEN_NOTERM) {
925 extra = 2;
926 }
927 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
928 blob->data+str_offset+align,
929 dest->private_length, flags);
930 }
931
932 if (flags & STR_LEN_NOTERM) {
933 extra = 1;
934 }
935
936 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
937 blob->data+str_offset, dest->private_length, flags);
938}
939
940/**
941 pull a string from a blob, returning a talloced char *
942
943 Currently only used by the UNIX search info level.
944
945 the string length is limited by 2 things:
946 - the data size in the blob
947 - the end of string (null termination)
948
949 on failure zero is returned and dest->s is set to NULL, otherwise the number
950 of bytes consumed in the blob is returned
951*/
952size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
953 TALLOC_CTX *mem_ctx,
954 DATA_BLOB *blob,
955 const char **dest,
956 uint16_t str_offset,
957 unsigned int flags)
958{
959 int extra = 0;
960 *dest = NULL;
961
962 if (!(flags & STR_ASCII) &&
963 ((flags & STR_UNICODE) ||
964 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
965 int align = 0;
966 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
967 align = 1;
968 }
969 if (flags & STR_LEN_NOTERM) {
970 extra = 2;
971 }
972 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
973 blob->data+str_offset+align,
974 -1, flags);
975 }
976
977 if (flags & STR_LEN_NOTERM) {
978 extra = 1;
979 }
980
981 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
982 blob->data+str_offset, -1, flags);
983}
984
985
986/*
987 append a string into a blob
988*/
989size_t smbcli_blob_append_string(struct smbcli_session *session,
990 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
991 const char *str, unsigned int flags)
992{
993 size_t max_len;
994 int len;
995
996 if (!str) return 0;
997
998 /* determine string type to use */
999 if (!(flags & (STR_ASCII|STR_UNICODE))) {
1000 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
1001 }
1002
1003 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
1004
1005 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length + max_len);
1006 if (!blob->data) {
1007 return 0;
1008 }
1009
1010 len = push_string(blob->data + blob->length, str, max_len, flags);
1011
1012 blob->length += len;
1013
1014 return len;
1015}
1016
1017/*
1018 pull a GUID structure from the wire. The buffer must be at least 16
1019 bytes long
1020 */
1021NTSTATUS smbcli_pull_guid(void *base, uint16_t offset,
1022 struct GUID *guid)
1023{
1024 DATA_BLOB blob;
1025
1026 ZERO_STRUCTP(guid);
1027
1028 blob.data = offset + (uint8_t *)base;
1029 blob.length = 16;
1030
1031 return GUID_from_ndr_blob(&blob, guid);
1032}
1033
1034/*
1035 push a guid onto the wire. The buffer must hold 16 bytes
1036 */
1037NTSTATUS smbcli_push_guid(void *base, uint16_t offset, const struct GUID *guid)
1038{
1039 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1040 NTSTATUS status;
1041 DATA_BLOB blob;
1042 status = GUID_to_ndr_blob(guid, tmp_ctx, &blob);
1043 if (!NT_STATUS_IS_OK(status)) {
1044 talloc_free(tmp_ctx);
1045 return status;
1046 }
1047 memcpy(offset + (uint8_t *)base, blob.data, blob.length);
1048 talloc_free(tmp_ctx);
1049 return NT_STATUS_OK;
1050}
Note: See TracBrowser for help on using the repository browser.