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 smbcli_request' structure in libsmb
27 #include "libcli/raw/libcliraw.h"
29 /* we over allocate the data buffer to prevent too many realloc calls */
30 #define REQ_OVER_ALLOCATION 256
32 /* assume that a character will not consume more than 3 bytes per char */
33 #define MAX_BYTES_PER_CHAR 3
35 /* destroy a request structure and return final status */
36 NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
40 /* this is the error code we give the application for when a
41 _send() call fails completely */
42 if (!req) return NT_STATUS_UNSUCCESSFUL;
45 /* remove it from the list of pending requests (a null op if
46 its not in the list) */
47 DLIST_REMOVE(req->transport->pending_recv, req);
50 /* ahh, its so nice to destroy a complex structure in such a
59 low-level function to setup a request buffer for a non-SMB packet
60 at the transport level
62 struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, uint_t size)
64 struct smbcli_request *req;
66 req = talloc_p(transport, struct smbcli_request);
72 /* setup the request context */
73 req->state = SMBCLI_REQUEST_INIT;
74 req->transport = transport;
79 /* over allocate by a small amount */
80 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
82 req->out.buffer = talloc(req, req->out.allocated);
83 if (!req->out.buffer) {
87 SIVAL(req->out.buffer, 0, 0);
94 setup a SMB packet at transport level
96 struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
97 uint8_t command, uint_t wct, uint_t buflen)
99 struct smbcli_request *req;
101 req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
103 if (!req) return NULL;
105 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
106 req->out.vwv = req->out.hdr + HDR_VWV;
108 req->out.data = req->out.vwv + VWV(wct) + 2;
109 req->out.data_size = buflen;
110 req->out.ptr = req->out.data;
112 SCVAL(req->out.hdr, HDR_WCT, wct);
113 SSVAL(req->out.vwv, VWV(wct), buflen);
115 memcpy(req->out.hdr, "\377SMB", 4);
116 SCVAL(req->out.hdr,HDR_COM,command);
118 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
119 SSVAL(req->out.hdr,HDR_FLG2, 0);
122 req->mid = smbcli_transport_next_mid(transport);
124 /* copy the pid, uid and mid to the request */
125 SSVAL(req->out.hdr, HDR_PID, 0);
126 SSVAL(req->out.hdr, HDR_UID, 0);
127 SSVAL(req->out.hdr, HDR_MID, req->mid);
128 SSVAL(req->out.hdr, HDR_TID,0);
129 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
130 SIVAL(req->out.hdr, HDR_RCLS, 0);
131 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
137 setup a reply in req->out with the given word count and initial data
138 buffer size. the caller will then fill in the command words and
139 data before calling smbcli_request_send() to send the reply on its
140 way. This interface is used before a session is setup.
142 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
143 uint8_t command, uint_t wct, uint_t buflen)
145 struct smbcli_request *req;
147 req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
149 if (!req) return NULL;
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);
162 setup a request for tree based commands
164 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
166 uint_t wct, uint_t buflen)
168 struct smbcli_request *req;
170 req = smbcli_request_setup_session(tree->session, command, wct, buflen);
173 SSVAL(req->out.hdr,HDR_TID,tree->tid);
179 grow the allocation of the data buffer portion of a reply
180 packet. Note that as this can reallocate the packet buffer this
181 invalidates any local pointers into the packet.
183 To cope with this req->out.ptr is supplied. This will be updated to
184 point at the same offset into the packet as before this call
186 static void smbcli_req_grow_allocation(struct smbcli_request *req, uint_t new_size)
191 delta = new_size - req->out.data_size;
192 if (delta + req->out.size <= req->out.allocated) {
193 /* it fits in the preallocation */
197 /* we need to realloc */
198 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
199 buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
201 smb_panic("out of memory in req_grow_allocation");
204 if (buf2 == req->out.buffer) {
205 /* the malloc library gave us the same pointer */
209 /* update the pointers into the packet */
210 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
211 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
212 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
213 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
215 req->out.buffer = buf2;
220 grow the data buffer portion of a reply packet. Note that as this
221 can reallocate the packet buffer this invalidates any local pointers
224 To cope with this req->out.ptr is supplied. This will be updated to
225 point at the same offset into the packet as before this call
227 void smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
231 smbcli_req_grow_allocation(req, new_size);
233 delta = new_size - req->out.data_size;
235 req->out.size += delta;
236 req->out.data_size += delta;
238 /* set the BCC to the new data size */
239 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
246 BOOL smbcli_request_send(struct smbcli_request *req)
248 if (IVAL(req->out.buffer, 0) == 0) {
249 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
252 smbcli_request_calculate_sign_mac(req);
254 smbcli_transport_send(req);
261 receive a response to a packet
263 BOOL smbcli_request_receive(struct smbcli_request *req)
265 /* req can be NULL when a send has failed. This eliminates lots of NULL
266 checks in each module */
267 if (!req) return False;
269 /* keep receiving packets until this one is replied to */
270 while (req->state <= SMBCLI_REQUEST_RECV) {
271 if (event_loop_once(req->transport->event.ctx) != 0) {
276 return req->state == SMBCLI_REQUEST_DONE;
281 receive another reply to a request - this is used for requests that
282 have multi-part replies (such as SMBtrans2)
284 BOOL smbcli_request_receive_more(struct smbcli_request *req)
286 req->state = SMBCLI_REQUEST_RECV;
287 DLIST_ADD(req->transport->pending_recv, req);
289 return smbcli_request_receive(req);
294 handle oplock break requests from the server - return True if the request was
297 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const char *hdr, const char *vwv)
299 /* we must be very fussy about what we consider an oplock break to avoid
300 matching readbraw replies */
301 if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
302 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
303 CVAL(hdr,HDR_COM) != SMBlockingX ||
304 SVAL(hdr, HDR_MID) != 0xFFFF ||
305 SVAL(vwv,VWV(6)) != 0 ||
306 SVAL(vwv,VWV(7)) != 0) {
310 if (transport->oplock.handler) {
311 uint16_t tid = SVAL(hdr, HDR_TID);
312 uint16_t fnum = SVAL(vwv,VWV(2));
313 uint8_t level = CVAL(vwv,VWV(3)+1);
314 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
321 wait for a reply to be received for a packet that just returns an error
322 code and nothing more
324 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
326 smbcli_request_receive(req);
327 return smbcli_request_destroy(req);
331 /* Return true if the last packet was in error */
332 BOOL smbcli_request_is_error(struct smbcli_request *req)
334 return NT_STATUS_IS_ERR(req->status);
338 append a string into the data portion of the request packet
340 return the number of bytes added to the packet
342 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
346 /* determine string type to use */
347 if (!(flags & (STR_ASCII|STR_UNICODE))) {
348 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
351 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
353 smbcli_req_grow_allocation(req, len + req->out.data_size);
355 len = push_string(req->out.data + req->out.data_size, str, len, flags);
357 smbcli_req_grow_data(req, len + req->out.data_size);
364 this is like smbcli_req_append_string but it also return the
365 non-terminated string byte length, which can be less than the number
366 of bytes consumed in the packet for 2 reasons:
368 1) the string in the packet may be null terminated
369 2) the string in the packet may need a 1 byte UCS2 alignment
371 this is used in places where the non-terminated string byte length is
372 placed in the packet as a separate field
374 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
379 /* determine string type to use */
380 if (!(flags & (STR_ASCII|STR_UNICODE))) {
381 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
384 /* see if an alignment byte will be used */
385 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
386 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
389 /* do the hard work */
390 ret = smbcli_req_append_string(req, str, flags);
392 /* see if we need to subtract the termination */
393 if (flags & STR_TERMINATE) {
394 diff += (flags & STR_UNICODE) ? 2 : 1;
408 push a string into the data portion of the request packet, growing it if necessary
409 this gets quite tricky - please be very careful to cover all cases when modifying this
411 if dest is NULL, then put the string at the end of the data portion of the packet
413 if dest_len is -1 then no limit applies
415 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
418 smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
419 size = smbcli_req_append_string(req, str, flags);
425 push a blob into the data portion of the request packet, growing it if necessary
426 this gets quite tricky - please be very careful to cover all cases when modifying this
428 if dest is NULL, then put the blob at the end of the data portion of the packet
430 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
432 smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
433 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
434 smbcli_req_grow_data(req, req->out.data_size + blob->length);
439 append raw bytes into the data portion of the request packet
440 return the number of bytes added
442 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
444 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
445 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
446 smbcli_req_grow_data(req, byte_len + req->out.data_size);
451 append variable block (type 5 buffer) into the data portion of the request packet
452 return the number of bytes added
454 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
456 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
457 SCVAL(req->out.data + req->out.data_size, 0, 5);
458 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
460 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
462 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
468 pull a UCS2 string from a request packet, returning a talloced unix string
470 the string length is limited by the 3 things:
471 - the data size in the request (end of packet)
472 - the passed 'byte_len' if it is not -1
473 - the end of string (null termination)
475 Note that 'byte_len' is the number of bytes in the packet
477 on failure zero is returned and *dest is set to NULL, otherwise the number
478 of bytes consumed in the packet is returned
480 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
481 char **dest, const char *src, int byte_len, uint_t flags)
483 int src_len, src_len2, alignment=0;
486 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
489 if (byte_len != -1) {
494 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
499 if (byte_len != -1 && src_len > byte_len) {
503 src_len2 = utf16_len_n(src, src_len);
505 /* ucs2 strings must be at least 2 bytes long */
511 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest);
517 return src_len2 + alignment;
521 pull a ascii string from a request packet, returning a talloced string
523 the string length is limited by the 3 things:
524 - the data size in the request (end of packet)
525 - the passed 'byte_len' if it is not -1
526 - the end of string (null termination)
528 Note that 'byte_len' is the number of bytes in the packet
530 on failure zero is returned and *dest is set to NULL, otherwise the number
531 of bytes consumed in the packet is returned
533 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
534 char **dest, const char *src, int byte_len, uint_t flags)
536 int src_len, src_len2;
539 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
544 if (byte_len != -1 && src_len > byte_len) {
547 src_len2 = strnlen(src, src_len);
548 if (src_len2 < src_len - 1) {
549 /* include the termination if we didn't reach the end of the packet */
553 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest);
564 pull a string from a request packet, returning a talloced string
566 the string length is limited by the 3 things:
567 - the data size in the request (end of packet)
568 - the passed 'byte_len' if it is not -1
569 - the end of string (null termination)
571 Note that 'byte_len' is the number of bytes in the packet
573 on failure zero is returned and *dest is set to NULL, otherwise the number
574 of bytes consumed in the packet is returned
576 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
577 char **dest, const char *src, int byte_len, uint_t flags)
579 if (!(flags & STR_ASCII) &&
580 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
581 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
584 return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
589 pull a DATA_BLOB from a reply packet, returning a talloced blob
590 make sure we don't go past end of packet
592 if byte_len is -1 then limit the blob only by packet size
594 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
598 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
601 return data_blob(NULL, 0);
604 if (byte_len != -1 && src_len > byte_len) {
608 return data_blob_talloc(mem_ctx, src, src_len);
611 /* check that a lump of data in a request is within the bounds of the data section of
613 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const char *ptr, uint32_t count)
615 /* be careful with wraparound! */
616 if (ptr < req->in.data ||
617 ptr >= req->in.data + req->in.data_size ||
618 count > req->in.data_size ||
619 ptr + count > req->in.data + req->in.data_size) {
626 pull a lump of data from a request packet
628 return False if any part is outside the data portion of the packet
630 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const char *src, int len, char *dest)
632 if (len == 0) return True;
634 if (smbcli_req_data_oob(req, src, len)) {
638 memcpy(dest, src, len);
644 put a NTTIME into a packet
646 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
648 SBVAL(base, offset, t);
652 pull a NTTIME from a packet
654 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
656 NTTIME ret = BVAL(base, offset);
661 pull a UCS2 string from a blob, returning a talloced unix string
663 the string length is limited by the 3 things:
664 - the data size in the blob
665 - the passed 'byte_len' if it is not -1
666 - the end of string (null termination)
668 Note that 'byte_len' is the number of bytes in the packet
670 on failure zero is returned and *dest is set to NULL, otherwise the number
671 of bytes consumed in the blob is returned
673 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
674 DATA_BLOB *blob, const char **dest,
675 const char *src, int byte_len, uint_t flags)
677 int src_len, src_len2, alignment=0;
681 if (src < (const char *)blob->data ||
682 src >= (const char *)(blob->data + blob->length)) {
687 src_len = blob->length - PTR_DIFF(src, blob->data);
689 if (byte_len != -1 && src_len > byte_len) {
693 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
704 src_len2 = utf16_len_n(src, src_len);
706 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
713 return src_len2 + alignment;
717 pull a ascii string from a blob, returning a talloced string
719 the string length is limited by the 3 things:
720 - the data size in the blob
721 - the passed 'byte_len' if it is not -1
722 - the end of string (null termination)
724 Note that 'byte_len' is the number of bytes in the blob
726 on failure zero is returned and *dest is set to NULL, otherwise the number
727 of bytes consumed in the blob is returned
729 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
730 DATA_BLOB *blob, const char **dest,
731 const char *src, int byte_len, uint_t flags)
733 int src_len, src_len2;
737 src_len = blob->length - PTR_DIFF(src, blob->data);
742 if (byte_len != -1 && src_len > byte_len) {
745 src_len2 = strnlen(src, src_len);
747 if (src_len2 < src_len - 1) {
748 /* include the termination if we didn't reach the end of the packet */
752 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
764 pull a string from a blob, returning a talloced WIRE_STRING
766 the string length is limited by the 3 things:
767 - the data size in the blob
768 - length field on the wire
769 - the end of string (null termination)
771 if STR_LEN8BIT is set in the flags then assume the length field is
772 8 bits, instead of 32
774 on failure zero is returned and dest->s is set to NULL, otherwise the number
775 of bytes consumed in the blob is returned
777 size_t smbcli_blob_pull_string(struct smbcli_session *session,
781 uint16_t len_offset, uint16_t str_offset,
787 if (flags & STR_LEN8BIT) {
788 if (len_offset > blob->length-1) {
791 dest->private_length = CVAL(blob->data, len_offset);
793 if (len_offset > blob->length-4) {
796 dest->private_length = IVAL(blob->data, len_offset);
800 if (!(flags & STR_ASCII) &&
801 ((flags & STR_UNICODE) ||
802 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
804 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
807 if (flags & STR_LEN_NOTERM) {
810 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
811 blob->data+str_offset+align,
812 dest->private_length, flags);
815 if (flags & STR_LEN_NOTERM) {
819 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
820 blob->data+str_offset, dest->private_length, flags);
824 pull a string from a blob, returning a talloced char *
826 Currently only used by the UNIX search info level.
828 the string length is limited by 2 things:
829 - the data size in the blob
830 - the end of string (null termination)
832 on failure zero is returned and dest->s is set to NULL, otherwise the number
833 of bytes consumed in the blob is returned
835 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
845 if (!(flags & STR_ASCII) &&
846 ((flags & STR_UNICODE) ||
847 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
849 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
852 if (flags & STR_LEN_NOTERM) {
855 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
856 blob->data+str_offset+align,
860 if (flags & STR_LEN_NOTERM) {
864 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
865 blob->data+str_offset, -1, flags);
870 append a string into a blob
872 size_t smbcli_blob_append_string(struct smbcli_session *session,
873 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
874 const char *str, uint_t flags)
881 /* determine string type to use */
882 if (!(flags & (STR_ASCII|STR_UNICODE))) {
883 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
886 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
888 blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
893 len = push_string(blob->data + blob->length, str, max_len, flags);