tests/krb5: Add tests for account salt calculation
[Samba.git] / source4 / libcli / raw / rawrequest.c
blob5805c2f66fc423cefc50701cf4aa8546294cd116
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2003
5 Copyright (C) James Myers 2003 <myersjj@samba.org>
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.
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.
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/>.
22 this file implements functions for manipulating the 'struct smbcli_request' structure in libsmb
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"
33 /* we over allocate the data buffer to prevent too many realloc calls */
34 #define REQ_OVER_ALLOCATION 0
36 /* assume that a character will not consume more than 3 bytes per char */
37 #define MAX_BYTES_PER_CHAR 3
39 /* setup the bufinfo used for strings and range checking */
40 void smb_setup_bufinfo(struct smbcli_request *req)
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;
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;
53 /* destroy a request structure and return final status */
54 _PUBLIC_ NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
56 NTSTATUS status;
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;
62 if (req->state == SMBCLI_REQUEST_ERROR &&
63 NT_STATUS_IS_OK(req->status)) {
64 req->status = NT_STATUS_INTERNAL_ERROR;
67 status = req->status;
69 if (!req->do_not_free) {
70 talloc_free(req);
73 return status;
78 setup a SMB packet at transport level
80 struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
81 uint8_t command, unsigned int wct, unsigned int buflen)
83 struct smbcli_request *req;
84 size_t size;
86 size = NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen;
88 req = talloc_zero(transport, struct smbcli_request);
89 if (!req) {
90 return NULL;
93 /* setup the request context */
94 req->state = SMBCLI_REQUEST_INIT;
95 req->transport = transport;
96 req->out.size = size;
98 /* over allocate by a small amount */
99 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
101 req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
102 if (!req->out.buffer) {
103 return NULL;
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;
113 SCVAL(req->out.hdr, HDR_WCT, wct);
114 SSVAL(req->out.vwv, VWV(wct), buflen);
116 memcpy(req->out.hdr, "\377SMB", 4);
117 SCVAL(req->out.hdr,HDR_COM,command);
119 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
120 SSVAL(req->out.hdr,HDR_FLG2, 0);
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);
131 return req;
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.
140 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
141 uint8_t command, unsigned int wct, size_t buflen)
143 struct smbcli_request *req;
145 req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
147 if (!req) return NULL;
149 smb1cli_session_set_id(session->smbXcli, session->vuid);
151 req->session = session;
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);
158 return req;
162 setup a request for tree based commands
164 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
165 uint8_t command,
166 unsigned int wct, unsigned int buflen)
168 struct smbcli_request *req;
170 req = smbcli_request_setup_session(tree->session, command, wct, buflen);
171 if (req) {
172 smb1cli_tcon_set_id(tree->smbXcli, tree->tid);
174 req->tree = tree;
175 SSVAL(req->out.hdr,HDR_TID,tree->tid);
177 return req;
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.
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
189 static void smbcli_req_grow_allocation(struct smbcli_request *req, unsigned int new_size)
191 int delta;
192 uint8_t *buf2;
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;
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");
207 if (buf2 == req->out.buffer) {
208 /* the malloc library gave us the same pointer */
209 return;
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);
218 req->out.buffer = buf2;
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.
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
230 static void smbcli_req_grow_data(struct smbcli_request *req, unsigned int new_size)
232 int delta;
234 smbcli_req_grow_allocation(req, new_size);
236 delta = new_size - req->out.data_size;
238 req->out.size += delta;
239 req->out.data_size += delta;
241 /* set the BCC to the new data size */
242 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
247 setup a chained reply in req->out with the given word count and
248 initial data buffer size.
250 NTSTATUS smbcli_chained_request_setup(struct smbcli_request *req,
251 uint8_t command,
252 unsigned int wct, size_t buflen)
254 size_t wct_ofs;
255 size_t size;
258 * here we only support one chained command
259 * If someone needs longer chains, the low
260 * level code should be used directly.
262 if (req->subreqs[0] != NULL) {
263 return NT_STATUS_INVALID_PARAMETER_MIX;
265 if (req->subreqs[1] != NULL) {
266 return NT_STATUS_INVALID_PARAMETER_MIX;
269 req->subreqs[0] = smbcli_transport_setup_subreq(req);
270 if (req->subreqs[0] == NULL) {
271 return NT_STATUS_NO_MEMORY;
274 wct_ofs = smb1cli_req_wct_ofs(req->subreqs, 1);
276 size = NBT_HDR_SIZE + wct_ofs + 1 + VWV(wct) + 2 + buflen;
278 req->out.size = size;
280 /* over allocate by a small amount */
281 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
283 req->out.buffer = talloc_zero_array(req, uint8_t, req->out.allocated);
284 if (!req->out.buffer) {
285 return NT_STATUS_NO_MEMORY;
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;
295 SCVAL(req->out.hdr, HDR_WCT, wct);
296 SSVAL(req->out.vwv, VWV(wct), buflen);
298 memcpy(req->out.hdr, "\377SMB", 4);
299 SCVAL(req->out.hdr,HDR_COM,command);
301 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
302 SSVAL(req->out.hdr,HDR_FLG2, 0);
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);
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);
320 if (req->tree != NULL) {
321 SSVAL(req->out.hdr, HDR_TID, req->tree->tid);
324 return NT_STATUS_OK;
328 advance to the next chained reply in a request
330 NTSTATUS smbcli_chained_advance(struct smbcli_request *req)
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;
341 if (req->subreqs[0] != NULL) {
342 return NT_STATUS_INVALID_PARAMETER_MIX;
344 if (req->subreqs[1] == NULL) {
345 return NT_STATUS_INVALID_PARAMETER_MIX;
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;
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;
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);
380 smb_setup_bufinfo(req);
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;
389 req->state = SMBCLI_REQUEST_DONE;
391 return NT_STATUS_OK;
396 send a message
398 bool smbcli_request_send(struct smbcli_request *req)
400 smbcli_transport_send(req);
401 return true;
406 receive a response to a packet
408 bool smbcli_request_receive(struct smbcli_request *req)
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;
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;
421 return req->state == SMBCLI_REQUEST_DONE;
425 wait for a reply to be received for a packet that just returns an error
426 code and nothing more
428 _PUBLIC_ NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
430 (void) smbcli_request_receive(req);
431 return smbcli_request_destroy(req);
435 /* Return true if the last packet was in error */
436 bool smbcli_request_is_error(struct smbcli_request *req)
438 return NT_STATUS_IS_ERR(req->status);
442 append a string into the data portion of the request packet
444 return the number of bytes added to the packet
446 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, unsigned int flags)
448 size_t len;
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;
455 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
457 smbcli_req_grow_allocation(req, len + req->out.data_size);
459 len = push_string(req->out.data + req->out.data_size, str, len, flags);
461 smbcli_req_grow_data(req, len + req->out.data_size);
463 return len;
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:
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
475 this is used in places where the non-terminated string byte length is
476 placed in the packet as a separate field
478 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, unsigned int flags, int *len)
480 int diff = 0;
481 size_t ret;
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;
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);
493 /* do the hard work */
494 ret = smbcli_req_append_string(req, str, flags);
496 /* see if we need to subtract the termination */
497 if (flags & STR_TERMINATE) {
498 diff += (flags & STR_UNICODE) ? 2 : 1;
501 if (ret >= diff) {
502 (*len) = ret - diff;
503 } else {
504 (*len) = ret;
507 return ret;
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
515 if dest is NULL, then put the string at the end of the data portion of the packet
517 if dest_len is -1 then no limit applies
519 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, unsigned int flags)
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;
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
532 if dest is NULL, then put the blob at the end of the data portion of the packet
534 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
536 if (blob->length > 0) {
537 smbcli_req_grow_allocation(req,
538 req->out.data_size + blob->length);
539 memcpy(req->out.data + req->out.data_size,
540 blob->data,
541 blob->length);
542 smbcli_req_grow_data(req, req->out.data_size + blob->length);
544 return blob->length;
548 append raw bytes into the data portion of the request packet
549 return the number of bytes added
551 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
553 if (byte_len > 0) {
554 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
555 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
556 smbcli_req_grow_data(req, byte_len + req->out.data_size);
558 return byte_len;
562 append variable block (type 5 buffer) into the data portion of the request packet
563 return the number of bytes added
565 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
567 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
568 SCVAL(req->out.data + req->out.data_size, 0, 5);
569 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
570 if (byte_len > 0) {
571 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
573 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
574 return byte_len + 3;
579 pull a UCS2 string from a request packet, returning a talloced unix string
581 the string length is limited by the 3 things:
582 - the data size in the request (end of packet)
583 - the passed 'byte_len' if it is not -1
584 - the end of string (null termination)
586 Note that 'byte_len' is the number of bytes in the packet
588 on failure zero is returned and *dest is set to NULL, otherwise the number
589 of bytes consumed in the packet is returned
591 static size_t smbcli_req_pull_ucs2(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
592 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
594 int src_len, src_len2, alignment=0;
595 bool ret;
596 size_t ret_size;
598 if (!(flags & STR_NOALIGN) && ucs2_align(bufinfo->align_base, src, flags)) {
599 src++;
600 alignment=1;
601 if (byte_len != -1) {
602 byte_len--;
606 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
607 if (src_len < 0) {
608 *dest = NULL;
609 return 0;
611 if (byte_len != -1 && src_len > byte_len) {
612 src_len = byte_len;
615 src_len2 = utf16_len_n(src, src_len);
617 /* ucs2 strings must be at least 2 bytes long */
618 if (src_len2 < 2) {
619 *dest = NULL;
620 return 0;
623 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
624 if (!ret) {
625 *dest = NULL;
626 return 0;
629 return src_len2 + alignment;
633 pull a ascii string from a request packet, returning a talloced string
635 the string length is limited by the 3 things:
636 - the data size in the request (end of packet)
637 - the passed 'byte_len' if it is not -1
638 - the end of string (null termination)
640 Note that 'byte_len' is the number of bytes in the packet
642 on failure zero is returned and *dest is set to NULL, otherwise the number
643 of bytes consumed in the packet is returned
645 size_t smbcli_req_pull_ascii(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
646 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
648 int src_len, src_len2;
649 bool ret;
650 size_t ret_size;
652 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
653 if (src_len < 0) {
654 *dest = NULL;
655 return 0;
657 if (byte_len != -1 && src_len > byte_len) {
658 src_len = byte_len;
660 src_len2 = strnlen((const char *)src, src_len);
661 if (src_len2 < src_len - 1) {
662 /* include the termination if we didn't reach the end of the packet */
663 src_len2++;
666 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest, &ret_size);
668 if (!ret) {
669 *dest = NULL;
670 return 0;
673 return ret_size;
677 pull a string from a request packet, returning a talloced string
679 the string length is limited by the 3 things:
680 - the data size in the request (end of packet)
681 - the passed 'byte_len' if it is not -1
682 - the end of string (null termination)
684 Note that 'byte_len' is the number of bytes in the packet
686 on failure zero is returned and *dest is set to NULL, otherwise the number
687 of bytes consumed in the packet is returned
689 size_t smbcli_req_pull_string(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx,
690 char **dest, const uint8_t *src, int byte_len, unsigned int flags)
692 if (!(flags & STR_ASCII) &&
693 (((flags & STR_UNICODE) || (bufinfo->flags & BUFINFO_FLAG_UNICODE)))) {
694 return smbcli_req_pull_ucs2(bufinfo, mem_ctx, dest, src, byte_len, flags);
697 return smbcli_req_pull_ascii(bufinfo, mem_ctx, dest, src, byte_len, flags);
702 pull a DATA_BLOB from a reply packet, returning a talloced blob
703 make sure we don't go past end of packet
705 if byte_len is -1 then limit the blob only by packet size
707 DATA_BLOB smbcli_req_pull_blob(struct request_bufinfo *bufinfo, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
709 int src_len;
711 src_len = bufinfo->data_size - PTR_DIFF(src, bufinfo->data);
713 if (src_len < 0) {
714 return data_blob(NULL, 0);
717 if (byte_len != -1 && src_len > byte_len) {
718 src_len = byte_len;
721 return data_blob_talloc(mem_ctx, src, src_len);
724 /* check that a lump of data in a request is within the bounds of the data section of
725 the packet */
726 static bool smbcli_req_data_oob(struct request_bufinfo *bufinfo, const uint8_t *ptr, uint32_t count)
728 /* be careful with wraparound! */
729 if ((uintptr_t)ptr < (uintptr_t)bufinfo->data ||
730 (uintptr_t)ptr >= (uintptr_t)bufinfo->data + bufinfo->data_size ||
731 count > bufinfo->data_size ||
732 (uintptr_t)ptr + count > (uintptr_t)bufinfo->data + bufinfo->data_size) {
733 return true;
735 return false;
739 pull a lump of data from a request packet
741 return false if any part is outside the data portion of the packet
743 bool smbcli_raw_pull_data(struct request_bufinfo *bufinfo, const uint8_t *src, int len, uint8_t *dest)
745 if (len == 0) return true;
747 if (smbcli_req_data_oob(bufinfo, src, len)) {
748 return false;
751 memcpy(dest, src, len);
752 return true;
757 put a NTTIME into a packet
759 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
761 SBVAL(base, offset, t);
765 pull a NTTIME from a packet
767 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
769 NTTIME ret = BVAL(base, offset);
770 return ret;
774 pull a UCS2 string from a blob, returning a talloced unix string
776 the string length is limited by the 3 things:
777 - the data size in the blob
778 - the passed 'byte_len' if it is not -1
779 - the end of string (null termination)
781 Note that 'byte_len' is the number of bytes in the packet
783 on failure zero is returned and *dest is set to NULL, otherwise the number
784 of bytes consumed in the blob is returned
786 size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
787 const DATA_BLOB *blob, const char **dest,
788 const uint8_t *src, int byte_len, unsigned int flags)
790 int src_len, src_len2, alignment=0;
791 size_t ret_size;
792 bool ret;
793 char *dest2;
795 if (src < blob->data ||
796 src >= (blob->data + blob->length)) {
797 *dest = NULL;
798 return 0;
801 src_len = blob->length - PTR_DIFF(src, blob->data);
803 if (byte_len != -1 && src_len > byte_len) {
804 src_len = byte_len;
807 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
808 src++;
809 alignment=1;
810 src_len--;
813 if (src_len < 2) {
814 *dest = NULL;
815 return 0;
818 src_len2 = utf16_len_n(src, src_len);
820 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
821 if (!ret) {
822 *dest = NULL;
823 return 0;
825 *dest = dest2;
827 return src_len2 + alignment;
831 pull a ascii string from a blob, returning a talloced string
833 the string length is limited by the 3 things:
834 - the data size in the blob
835 - the passed 'byte_len' if it is not -1
836 - the end of string (null termination)
838 Note that 'byte_len' is the number of bytes in the blob
840 on failure zero is returned and *dest is set to NULL, otherwise the number
841 of bytes consumed in the blob is returned
843 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
844 const DATA_BLOB *blob, const char **dest,
845 const uint8_t *src, int byte_len, unsigned int flags)
847 int src_len, src_len2;
848 size_t ret_size;
849 bool ret;
850 char *dest2;
852 src_len = blob->length - PTR_DIFF(src, blob->data);
853 if (src_len < 0) {
854 *dest = NULL;
855 return 0;
857 if (byte_len != -1 && src_len > byte_len) {
858 src_len = byte_len;
860 src_len2 = strnlen((const char *)src, src_len);
862 if (src_len2 < src_len - 1) {
863 /* include the termination if we didn't reach the end of the packet */
864 src_len2++;
867 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2, &ret_size);
869 if (!ret) {
870 *dest = NULL;
871 return 0;
873 *dest = dest2;
875 return ret_size;
879 pull a string from a blob, returning a talloced struct smb_wire_string
881 the string length is limited by the 3 things:
882 - the data size in the blob
883 - length field on the wire
884 - the end of string (null termination)
886 if STR_LEN8BIT is set in the flags then assume the length field is
887 8 bits, instead of 32
889 on failure zero is returned and dest->s is set to NULL, otherwise the number
890 of bytes consumed in the blob is returned
892 size_t smbcli_blob_pull_string(struct smbcli_session *session,
893 TALLOC_CTX *mem_ctx,
894 const DATA_BLOB *blob,
895 struct smb_wire_string *dest,
896 uint16_t len_offset, uint16_t str_offset,
897 unsigned int flags)
899 int extra;
900 dest->s = NULL;
902 if (!(flags & STR_ASCII)) {
903 /* this is here to cope with SMB2 calls using the SMB
904 parsers. SMB2 will pass smbcli_session==NULL, which forces
905 unicode on (as used by SMB2) */
906 if (session == NULL) {
907 flags |= STR_UNICODE;
908 } else if (session->transport->negotiate.capabilities & CAP_UNICODE) {
909 flags |= STR_UNICODE;
913 if (flags & STR_LEN8BIT) {
914 if (len_offset > blob->length-1) {
915 return 0;
917 dest->private_length = CVAL(blob->data, len_offset);
918 } else {
919 if (len_offset > blob->length-4) {
920 return 0;
922 dest->private_length = IVAL(blob->data, len_offset);
924 extra = 0;
925 dest->s = NULL;
926 if (!(flags & STR_ASCII) && (flags & STR_UNICODE)) {
927 int align = 0;
928 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
929 align = 1;
931 if (flags & STR_LEN_NOTERM) {
932 extra = 2;
934 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
935 blob->data+str_offset+align,
936 dest->private_length, flags);
939 if (flags & STR_LEN_NOTERM) {
940 extra = 1;
943 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
944 blob->data+str_offset, dest->private_length, flags);
948 pull a string from a blob, returning a talloced char *
950 Currently only used by the UNIX search info level.
952 the string length is limited by 2 things:
953 - the data size in the blob
954 - the end of string (null termination)
956 on failure zero is returned and dest->s is set to NULL, otherwise the number
957 of bytes consumed in the blob is returned
959 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
960 TALLOC_CTX *mem_ctx,
961 DATA_BLOB *blob,
962 const char **dest,
963 uint16_t str_offset,
964 unsigned int flags)
966 int extra = 0;
967 *dest = NULL;
969 if (!(flags & STR_ASCII) &&
970 ((flags & STR_UNICODE) ||
971 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
972 int align = 0;
973 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
974 align = 1;
976 if (flags & STR_LEN_NOTERM) {
977 extra = 2;
979 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
980 blob->data+str_offset+align,
981 -1, flags);
984 if (flags & STR_LEN_NOTERM) {
985 extra = 1;
988 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
989 blob->data+str_offset, -1, flags);
994 append a string into a blob
996 size_t smbcli_blob_append_string(struct smbcli_session *session,
997 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
998 const char *str, unsigned int flags)
1000 size_t max_len;
1001 int len;
1003 if (!str) return 0;
1005 /* determine string type to use */
1006 if (!(flags & (STR_ASCII|STR_UNICODE))) {
1007 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
1010 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
1012 blob->data = talloc_realloc(mem_ctx, blob->data, uint8_t, blob->length + max_len);
1013 if (!blob->data) {
1014 return 0;
1017 len = push_string(blob->data + blob->length, str, max_len, flags);
1019 blob->length += len;
1021 return len;
1025 pull a GUID structure from the wire. The buffer must be at least 16
1026 bytes long
1028 NTSTATUS smbcli_pull_guid(void *base, uint16_t offset,
1029 struct GUID *guid)
1031 DATA_BLOB blob;
1033 ZERO_STRUCTP(guid);
1035 blob.data = offset + (uint8_t *)base;
1036 blob.length = 16;
1038 return GUID_from_ndr_blob(&blob, guid);
1042 push a guid onto the wire. The buffer must hold 16 bytes
1044 NTSTATUS smbcli_push_guid(void *base, uint16_t offset, const struct GUID *guid)
1046 TALLOC_CTX *tmp_ctx = talloc_new(NULL);
1047 NTSTATUS status;
1048 DATA_BLOB blob;
1049 status = GUID_to_ndr_blob(guid, tmp_ctx, &blob);
1050 if (!NT_STATUS_IS_OK(status)) {
1051 talloc_free(tmp_ctx);
1052 return status;
1054 memcpy(offset + (uint8_t *)base, blob.data, blob.length);
1055 talloc_free(tmp_ctx);
1056 return NT_STATUS_OK;