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 2 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, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 this file implements functions for manipulating the 'struct cli_request' structure in libsmb
28 /* we over allocate the data buffer to prevent too many realloc calls */
29 #define REQ_OVER_ALLOCATION 256
31 /* assume that a character will not consume more than 3 bytes per char */
32 #define MAX_BYTES_PER_CHAR 3
34 /* destroy a request structure and return final status */
35 NTSTATUS cli_request_destroy(struct cli_request *req)
39 /* this is the error code we give the application for when a
40 _send() call fails completely */
41 if (!req) return NT_STATUS_UNSUCCESSFUL;
43 /* remove it from the list of pending requests (a null op if
44 its not in the list) */
45 DLIST_REMOVE(req->transport->pending_requests, req);
47 /* ahh, its so nice to destroy a complex structure in such a
50 talloc_destroy(req->mem_ctx);
56 low-level function to setup a request buffer for a non-SMB packet
57 at the transport level
59 struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, uint_t size)
61 struct cli_request *req;
64 /* each request gets its own talloc context. The request
65 structure itself is also allocated inside this context,
66 so we need to allocate it before we construct the request
68 mem_ctx = talloc_init("cli_request");
73 req = talloc(mem_ctx, sizeof(struct cli_request));
79 /* setup the request context */
80 req->mem_ctx = mem_ctx;
81 req->transport = transport;
86 /* over allocate by a small amount */
87 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
89 req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
90 if (!req->out.buffer) {
94 SIVAL(req->out.buffer, 0, 0);
101 setup a SMB packet at transport level
103 struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
104 uint8 command, unsigned wct, unsigned buflen)
106 struct cli_request *req;
108 req = cli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
110 if (!req) return NULL;
112 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
113 req->out.vwv = req->out.hdr + HDR_VWV;
115 req->out.data = req->out.vwv + VWV(wct) + 2;
116 req->out.data_size = buflen;
117 req->out.ptr = req->out.data;
119 SCVAL(req->out.hdr, HDR_WCT, wct);
120 SSVAL(req->out.vwv, VWV(wct), buflen);
122 memcpy(req->out.hdr, "\377SMB", 4);
123 SCVAL(req->out.hdr,HDR_COM,command);
125 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
126 SSVAL(req->out.hdr,HDR_FLG2, 0);
129 req->mid = cli_transport_next_mid(transport);
131 /* copy the pid, uid and mid to the request */
132 SSVAL(req->out.hdr, HDR_PID, 0);
133 SSVAL(req->out.hdr, HDR_UID, 0);
134 SSVAL(req->out.hdr, HDR_MID, req->mid);
135 SSVAL(req->out.hdr, HDR_TID,0);
136 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
137 SIVAL(req->out.hdr, HDR_RCLS, 0);
138 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
144 setup a reply in req->out with the given word count and initial data
145 buffer size. the caller will then fill in the command words and
146 data before calling cli_request_send() to send the reply on its
147 way. This interface is used before a session is setup.
149 struct cli_request *cli_request_setup_session(struct cli_session *session,
150 uint8 command, unsigned wct, unsigned buflen)
152 struct cli_request *req;
156 req = cli_request_setup_transport(session->transport, command, wct, buflen);
158 if (!req) return NULL;
160 req->session = session;
162 flags2 = FLAGS2_LONG_PATH_COMPONENTS;
163 capabilities = session->transport->negotiate.capabilities;
165 if (capabilities & CAP_UNICODE) {
166 flags2 |= FLAGS2_UNICODE_STRINGS;
168 if (capabilities & CAP_STATUS32) {
169 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
171 if (capabilities & CAP_EXTENDED_SECURITY) {
172 flags2 |= FLAGS2_EXTENDED_SECURITY;
174 if (session->transport->negotiate.sign_info.doing_signing) {
175 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
178 SSVAL(req->out.hdr, HDR_FLG2, flags2);
179 SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
180 SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
181 SSVAL(req->out.hdr, HDR_UID, session->vuid);
187 setup a request for tree based commands
189 struct cli_request *cli_request_setup(struct cli_tree *tree,
191 unsigned wct, unsigned buflen)
193 struct cli_request *req;
195 req = cli_request_setup_session(tree->session, command, wct, buflen);
198 SSVAL(req->out.hdr,HDR_TID,tree->tid);
204 grow the allocation of the data buffer portion of a reply
205 packet. Note that as this can reallocate the packet buffer this
206 invalidates any local pointers into the packet.
208 To cope with this req->out.ptr is supplied. This will be updated to
209 point at the same offset into the packet as before this call
211 static void cli_req_grow_allocation(struct cli_request *req, unsigned new_size)
216 delta = new_size - req->out.data_size;
217 if (delta + req->out.size <= req->out.allocated) {
218 /* it fits in the preallocation */
222 /* we need to realloc */
223 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
224 buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
226 smb_panic("out of memory in req_grow_allocation");
229 if (buf2 == req->out.buffer) {
230 /* the malloc library gave us the same pointer */
234 /* update the pointers into the packet */
235 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
236 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
237 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
238 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
240 req->out.buffer = buf2;
245 grow the data buffer portion of a reply packet. Note that as this
246 can reallocate the packet buffer this invalidates any local pointers
249 To cope with this req->out.ptr is supplied. This will be updated to
250 point at the same offset into the packet as before this call
252 static void cli_req_grow_data(struct cli_request *req, unsigned new_size)
256 cli_req_grow_allocation(req, new_size);
258 delta = new_size - req->out.data_size;
260 req->out.size += delta;
261 req->out.data_size += delta;
263 /* set the BCC to the new data size */
264 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
270 BOOL cli_request_send(struct cli_request *req)
274 if (IVAL(req->out.buffer, 0) == 0) {
275 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
278 cli_request_calculate_sign_mac(req);
280 ret = cli_sock_write(req->transport->socket, req->out.buffer, req->out.size);
282 if (req->out.size != ret) {
283 req->transport->error.etype = ETYPE_SOCKET;
284 req->transport->error.e.socket_error = SOCKET_WRITE_ERROR;
285 DEBUG(0,("Error writing %d bytes to server - %s\n",
286 (int)req->out.size, strerror(errno)));
290 /* add it to the list of pending requests */
291 DLIST_ADD(req->transport->pending_requests, req);
298 receive a response to a packet
300 BOOL cli_request_receive(struct cli_request *req)
302 /* req can be NULL when a send has failed. This eliminates lots of NULL
303 checks in each module */
304 if (!req) return False;
306 /* keep receiving packets until this one is replied to */
307 while (!req->in.buffer) {
308 if (!cli_transport_select(req->transport)) {
312 if (!cli_request_receive_next(req->transport)) {
313 cli_transport_close(req->transport);
314 req->status = NT_STATUS_UNEXPECTED_NETWORK_ERROR;
324 handle oplock break requests from the server - return True if the request was
327 static BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
329 /* we must be very fussy about what we consider an oplock break to avoid
330 matching readbraw replies */
331 if (len != MIN_SMB_SIZE + VWV(8) ||
332 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
333 CVAL(hdr,HDR_COM) != SMBlockingX ||
334 SVAL(hdr, HDR_MID) != 0xFFFF ||
335 SVAL(vwv,VWV(6)) != 0 ||
336 SVAL(vwv,VWV(7)) != 0) {
340 if (transport->oplock.handler) {
341 uint16 tid = SVAL(hdr, HDR_TID);
342 uint16 fnum = SVAL(vwv,VWV(2));
343 uint8 level = CVAL(vwv,VWV(3));
344 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
352 receive an async message from the server
353 this function assumes that the caller already knows that the socket is readable
354 and that there is a packet waiting
356 The packet is not actually returned by this function, instead any
357 registered async message handlers are called
359 return True if a packet was successfully received and processed
360 return False if the socket appears to be dead
362 BOOL cli_request_receive_next(struct cli_transport *transport)
366 char header[NBT_HDR_SIZE];
367 char *buffer, *hdr, *vwv;
369 struct cli_request *req;
372 len = cli_sock_read(transport->socket, header, 4);
377 len = smb_len(header);
379 mem_ctx = talloc_init("cli_request_receive_next");
381 /* allocate the incoming buffer at the right size */
382 buffer = talloc(mem_ctx, len+NBT_HDR_SIZE);
384 talloc_destroy(mem_ctx);
388 /* fill in the already received header */
389 memcpy(buffer, header, NBT_HDR_SIZE);
391 ret = cli_sock_read(transport->socket, buffer + NBT_HDR_SIZE, len);
392 /* If the server is not responding, note that now */
397 hdr = buffer+NBT_HDR_SIZE;
400 /* see if it could be an oplock break request */
401 if (handle_oplock_break(transport, len, hdr, vwv)) {
405 /* at this point we need to check for a readbraw reply, as these can be any length */
406 if (transport->readbraw_pending) {
407 transport->readbraw_pending = 0;
409 /* it must match the first entry in the pending queue as the client is not allowed
410 to have outstanding readbraw requests */
411 req = transport->pending_requests;
414 req->in.buffer = buffer;
415 talloc_steal(mem_ctx, req->mem_ctx, buffer);
416 req->in.size = len + NBT_HDR_SIZE;
417 req->in.allocated = req->in.size;
421 if (len >= MIN_SMB_SIZE) {
422 /* extract the mid for matching to pending requests */
423 mid = SVAL(hdr, HDR_MID);
424 wct = CVAL(hdr, HDR_WCT);
427 /* match the incoming request against the list of pending requests */
428 for (req=transport->pending_requests; req; req=req->next) {
429 if (req->mid == mid) break;
433 DEBUG(3,("Discarding unmatched reply with mid %d\n", mid));
437 /* fill in the 'in' portion of the matching request */
438 req->in.buffer = buffer;
439 talloc_steal(mem_ctx, req->mem_ctx, buffer);
440 req->in.size = len + NBT_HDR_SIZE;
441 req->in.allocated = req->in.size;
443 /* handle non-SMB replies */
444 if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE) {
448 if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
449 DEBUG(2,("bad reply size for mid %d\n", mid));
450 req->status = NT_STATUS_UNSUCCESSFUL;
457 if (req->in.size >= NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct)) {
458 req->in.data = req->in.vwv + VWV(wct) + 2;
459 req->in.data_size = SVAL(req->in.vwv, VWV(wct));
460 if (req->in.size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct) + req->in.data_size) {
461 DEBUG(3,("bad data size for mid %d\n", mid));
462 /* blergh - w2k3 gives a bogus data size values in some
464 req->in.data_size = req->in.size - (NBT_HDR_SIZE + MIN_SMB_SIZE + VWV(wct));
467 req->in.ptr = req->in.data;
468 req->flags2 = SVAL(req->in.hdr, HDR_FLG2);
470 if (!(req->flags2 & FLAGS2_32_BIT_ERROR_CODES)) {
471 transport->error.etype = ETYPE_DOS;
472 transport->error.e.dos.eclass = CVAL(req->in.hdr,HDR_RCLS);
473 transport->error.e.dos.ecode = SVAL(req->in.hdr,HDR_ERR);
474 req->status = dos_to_ntstatus(transport->error.e.dos.eclass,
475 transport->error.e.dos.ecode);
477 transport->error.etype = ETYPE_NT;
478 transport->error.e.nt_status = NT_STATUS(IVAL(req->in.hdr, HDR_RCLS));
479 req->status = transport->error.e.nt_status;
482 if (!cli_request_check_sign_mac(req)) {
483 transport->error.etype = ETYPE_SOCKET;
484 transport->error.e.socket_error = SOCKET_READ_BAD_SIG;
489 /* if this request has an async handler then call that to
490 notify that the reply has been received. This might destroy
491 the request so it must happen last */
497 talloc_destroy(mem_ctx);
503 wait for a reply to be received for a packet that just returns an error
504 code and nothing more
506 NTSTATUS cli_request_simple_recv(struct cli_request *req)
508 cli_request_receive(req);
509 return cli_request_destroy(req);
513 /* Return true if the last packet was in error */
514 BOOL cli_request_is_error(struct cli_request *req)
516 return NT_STATUS_IS_ERR(req->status);
520 append a string into the data portion of the request packet
522 return the number of bytes added to the packet
524 size_t cli_req_append_string(struct cli_request *req, const char *str, unsigned flags)
528 /* determine string type to use */
529 if (!(flags & (STR_ASCII|STR_UNICODE))) {
530 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
533 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
535 cli_req_grow_allocation(req, len + req->out.data_size);
537 len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
539 cli_req_grow_data(req, len + req->out.data_size);
545 this is like cli_req_append_string but it also return the
546 non-terminated string byte length, which can be less than the number
547 of bytes consumed in the packet for 2 reasons:
549 1) the string in the packet may be null terminated
550 2) the string in the packet may need a 1 byte UCS2 alignment
552 this is used in places where the non-terminated string byte length is
553 placed in the packet as a separate field
555 size_t cli_req_append_string_len(struct cli_request *req, const char *str, unsigned flags, int *len)
560 /* determine string type to use */
561 if (!(flags & (STR_ASCII|STR_UNICODE))) {
562 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
565 /* see if an alignment byte will be used */
566 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
567 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
570 /* do the hard work */
571 ret = cli_req_append_string(req, str, flags);
573 /* see if we need to subtract the termination */
574 if (flags & STR_TERMINATE) {
575 diff += (flags & STR_UNICODE) ? 2 : 1;
589 push a string into the data portion of the request packet, growing it if necessary
590 this gets quite tricky - please be very careful to cover all cases when modifying this
592 if dest is NULL, then put the string at the end of the data portion of the packet
594 if dest_len is -1 then no limit applies
596 size_t cli_req_append_ascii4(struct cli_request *req, const char *str, unsigned flags)
599 cli_req_append_bytes(req, (const uint8 *)"\4", 1);
600 size = cli_req_append_string(req, str, flags);
606 push a blob into the data portion of the request packet, growing it if necessary
607 this gets quite tricky - please be very careful to cover all cases when modifying this
609 if dest is NULL, then put the blob at the end of the data portion of the packet
611 size_t cli_req_append_blob(struct cli_request *req, const DATA_BLOB *blob)
613 cli_req_grow_allocation(req, req->out.data_size + blob->length);
614 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
615 cli_req_grow_data(req, req->out.data_size + blob->length);
620 append raw bytes into the data portion of the request packet
621 return the number of bytes added
623 size_t cli_req_append_bytes(struct cli_request *req, const uint8 *bytes, size_t byte_len)
625 cli_req_grow_allocation(req, byte_len + req->out.data_size);
626 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
627 cli_req_grow_data(req, byte_len + req->out.data_size);
632 append variable block (type 5 buffer) into the data portion of the request packet
633 return the number of bytes added
635 size_t cli_req_append_var_block(struct cli_request *req, const uint8 *bytes, uint16 byte_len)
637 cli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
638 SCVAL(req->out.data + req->out.data_size, 0, 5);
639 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
641 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
643 cli_req_grow_data(req, byte_len + 3 + req->out.data_size);
649 pull a UCS2 string from a request packet, returning a talloced unix string
651 the string length is limited by the 3 things:
652 - the data size in the request (end of packet)
653 - the passed 'byte_len' if it is not -1
654 - the end of string (null termination)
656 Note that 'byte_len' is the number of bytes in the packet
658 on failure zero is returned and *dest is set to NULL, otherwise the number
659 of bytes consumed in the packet is returned
661 static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
662 char **dest, const char *src, int byte_len, unsigned flags)
664 int src_len, src_len2, alignment=0;
667 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
670 if (byte_len != -1) {
675 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
680 if (byte_len != -1 && src_len > byte_len) {
684 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
685 if (src_len2 < src_len - 2) {
686 /* include the termination if we didn't reach the end of the packet */
690 /* ucs2 strings must be at least 2 bytes long */
696 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
702 return src_len2 + alignment;
706 pull a ascii string from a request packet, returning a talloced string
708 the string length is limited by the 3 things:
709 - the data size in the request (end of packet)
710 - the passed 'byte_len' if it is not -1
711 - the end of string (null termination)
713 Note that 'byte_len' is the number of bytes in the packet
715 on failure zero is returned and *dest is set to NULL, otherwise the number
716 of bytes consumed in the packet is returned
718 size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
719 char **dest, const char *src, int byte_len, unsigned flags)
721 int src_len, src_len2;
724 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
729 if (byte_len != -1 && src_len > byte_len) {
732 src_len2 = strnlen(src, src_len);
733 if (src_len2 < src_len - 1) {
734 /* include the termination if we didn't reach the end of the packet */
738 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
749 pull a string from a request packet, returning a talloced string
751 the string length is limited by the 3 things:
752 - the data size in the request (end of packet)
753 - the passed 'byte_len' if it is not -1
754 - the end of string (null termination)
756 Note that 'byte_len' is the number of bytes in the packet
758 on failure zero is returned and *dest is set to NULL, otherwise the number
759 of bytes consumed in the packet is returned
761 size_t cli_req_pull_string(struct cli_request *req, TALLOC_CTX *mem_ctx,
762 char **dest, const char *src, int byte_len, unsigned flags)
764 if (!(flags & STR_ASCII) &&
765 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
766 return cli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
769 return cli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
774 pull a DATA_BLOB from a reply packet, returning a talloced blob
775 make sure we don't go past end of packet
777 if byte_len is -1 then limit the blob only by packet size
779 DATA_BLOB cli_req_pull_blob(struct cli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
783 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
786 return data_blob(NULL, 0);
789 if (byte_len != -1 && src_len > byte_len) {
793 return data_blob_talloc(mem_ctx, src, src_len);
796 /* check that a lump of data in a request is within the bounds of the data section of
798 static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32 count)
800 /* be careful with wraparound! */
801 if (ptr < req->in.data ||
802 ptr >= req->in.data + req->in.data_size ||
803 count > req->in.data_size ||
804 ptr + count > req->in.data + req->in.data_size) {
811 pull a lump of data from a request packet
813 return False if any part is outside the data portion of the packet
815 BOOL cli_raw_pull_data(struct cli_request *req, const char *src, int len, char *dest)
817 if (len == 0) return True;
819 if (cli_req_data_oob(req, src, len)) {
823 memcpy(dest, src, len);
829 put a NTTIME into a packet
832 void cli_push_nttime(void *base, uint16 offset, NTTIME *t)
834 SIVAL(base, offset, t->low);
835 SIVAL(base, offset+4, t->high);
839 pull a NTTIME from a packet
841 NTTIME cli_pull_nttime(void *base, uint16 offset)
844 ret.low = IVAL(base, offset);
845 ret.high = IVAL(base, offset+4);
850 pull a UCS2 string from a blob, returning a talloced unix string
852 the string length is limited by the 3 things:
853 - the data size in the blob
854 - the passed 'byte_len' if it is not -1
855 - the end of string (null termination)
857 Note that 'byte_len' is the number of bytes in the packet
859 on failure zero is returned and *dest is set to NULL, otherwise the number
860 of bytes consumed in the blob is returned
862 static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
863 DATA_BLOB *blob, const char **dest,
864 const char *src, int byte_len, unsigned flags)
866 int src_len, src_len2, alignment=0;
869 if (src < (const char *)blob->data ||
870 src >= (const char *)(blob->data + blob->length)) {
875 src_len = blob->length - PTR_DIFF(src, blob->data);
877 if (byte_len != -1 && src_len > byte_len) {
881 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
892 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
894 if (src_len2 < src_len - 2) {
895 /* include the termination if we didn't reach the end of the packet */
899 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
905 return src_len2 + alignment;
909 pull a ascii string from a blob, returning a talloced string
911 the string length is limited by the 3 things:
912 - the data size in the blob
913 - the passed 'byte_len' if it is not -1
914 - the end of string (null termination)
916 Note that 'byte_len' is the number of bytes in the blob
918 on failure zero is returned and *dest is set to NULL, otherwise the number
919 of bytes consumed in the blob is returned
921 static size_t cli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
922 DATA_BLOB *blob, const char **dest,
923 const char *src, int byte_len, unsigned flags)
925 int src_len, src_len2;
928 src_len = blob->length - PTR_DIFF(src, blob->data);
933 if (byte_len != -1 && src_len > byte_len) {
936 src_len2 = strnlen(src, src_len);
938 if (src_len2 < src_len - 1) {
939 /* include the termination if we didn't reach the end of the packet */
943 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
954 pull a string from a blob, returning a talloced WIRE_STRING
956 the string length is limited by the 3 things:
957 - the data size in the blob
958 - length field on the wire
959 - the end of string (null termination)
961 if STR_LEN8BIT is set in the flags then assume the length field is
962 8 bits, instead of 32
964 on failure zero is returned and dest->s is set to NULL, otherwise the number
965 of bytes consumed in the blob is returned
967 size_t cli_blob_pull_string(struct cli_session *session,
971 uint16 len_offset, uint16 str_offset,
977 if (len_offset > blob->length-4) {
980 if (flags & STR_LEN8BIT) {
981 dest->private_length = CVAL(blob->data, len_offset);
983 dest->private_length = IVAL(blob->data, len_offset);
987 if (!(flags & STR_ASCII) &&
988 ((flags & STR_UNICODE) ||
989 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
991 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
994 if (flags & STR_LEN_NOTERM) {
997 return align + extra + cli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
998 blob->data+str_offset+align,
999 dest->private_length, flags);
1002 if (flags & STR_LEN_NOTERM) {
1006 return extra + cli_blob_pull_ascii(mem_ctx, blob, &dest->s,
1007 blob->data+str_offset, dest->private_length, flags);
1011 append a string into a blob
1013 size_t cli_blob_append_string(struct cli_session *session,
1014 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
1015 const char *str, unsigned flags)
1022 /* determine string type to use */
1023 if (!(flags & (STR_ASCII|STR_UNICODE))) {
1024 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
1027 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
1029 blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
1034 len = push_string(NULL, blob->data + blob->length, str, max_len, flags);
1036 blob->length += len;