source: branches/samba-3.5.x/source4/libcli/raw/rawrequest.c

Last change on this file was 414, checked in by Herwig Bauernfeind, 15 years ago

Samba 3.5.0: Initial import

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