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
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 smbcli_request_destroy(struct smbcli_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;
44 /* remove it from the list of pending requests (a null op if
45 its not in the list) */
46 DLIST_REMOVE(req->transport->pending_recv, req);
49 /* ahh, its so nice to destroy a complex structure in such a
58 low-level function to setup a request buffer for a non-SMB packet
59 at the transport level
61 struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, uint_t size)
63 struct smbcli_request *req;
65 req = talloc_named(NULL, sizeof(struct smbcli_request), "smcli_request");
71 /* setup the request context */
72 req->state = SMBCLI_REQUEST_INIT;
73 req->transport = transport;
78 /* over allocate by a small amount */
79 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
81 req->out.buffer = talloc(req, req->out.allocated);
82 if (!req->out.buffer) {
86 SIVAL(req->out.buffer, 0, 0);
93 setup a SMB packet at transport level
95 struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
96 uint8_t command, uint_t wct, uint_t buflen)
98 struct smbcli_request *req;
100 req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
102 if (!req) return NULL;
104 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
105 req->out.vwv = req->out.hdr + HDR_VWV;
107 req->out.data = req->out.vwv + VWV(wct) + 2;
108 req->out.data_size = buflen;
109 req->out.ptr = req->out.data;
111 SCVAL(req->out.hdr, HDR_WCT, wct);
112 SSVAL(req->out.vwv, VWV(wct), buflen);
114 memcpy(req->out.hdr, "\377SMB", 4);
115 SCVAL(req->out.hdr,HDR_COM,command);
117 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
118 SSVAL(req->out.hdr,HDR_FLG2, 0);
121 req->mid = smbcli_transport_next_mid(transport);
123 /* copy the pid, uid and mid to the request */
124 SSVAL(req->out.hdr, HDR_PID, 0);
125 SSVAL(req->out.hdr, HDR_UID, 0);
126 SSVAL(req->out.hdr, HDR_MID, req->mid);
127 SSVAL(req->out.hdr, HDR_TID,0);
128 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
129 SIVAL(req->out.hdr, HDR_RCLS, 0);
130 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
136 setup a reply in req->out with the given word count and initial data
137 buffer size. the caller will then fill in the command words and
138 data before calling smbcli_request_send() to send the reply on its
139 way. This interface is used before a session is setup.
141 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
142 uint8_t command, uint_t wct, uint_t buflen)
144 struct smbcli_request *req;
146 uint32_t capabilities;
148 req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
150 if (!req) return NULL;
152 req->session = session;
154 flags2 = FLAGS2_LONG_PATH_COMPONENTS;
155 capabilities = session->transport->negotiate.capabilities;
157 if (capabilities & CAP_UNICODE) {
158 flags2 |= FLAGS2_UNICODE_STRINGS;
160 if (capabilities & CAP_STATUS32) {
161 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
163 if (capabilities & CAP_EXTENDED_SECURITY) {
164 flags2 |= FLAGS2_EXTENDED_SECURITY;
166 if (session->transport->negotiate.sign_info.doing_signing) {
167 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
170 SSVAL(req->out.hdr, HDR_FLG2, flags2);
171 SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
172 SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
173 SSVAL(req->out.hdr, HDR_UID, session->vuid);
179 setup a request for tree based commands
181 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
183 uint_t wct, uint_t buflen)
185 struct smbcli_request *req;
187 req = smbcli_request_setup_session(tree->session, command, wct, buflen);
190 SSVAL(req->out.hdr,HDR_TID,tree->tid);
196 grow the allocation of the data buffer portion of a reply
197 packet. Note that as this can reallocate the packet buffer this
198 invalidates any local pointers into the packet.
200 To cope with this req->out.ptr is supplied. This will be updated to
201 point at the same offset into the packet as before this call
203 static void smbcli_req_grow_allocation(struct smbcli_request *req, uint_t new_size)
208 delta = new_size - req->out.data_size;
209 if (delta + req->out.size <= req->out.allocated) {
210 /* it fits in the preallocation */
214 /* we need to realloc */
215 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
216 buf2 = talloc_realloc(req->out.buffer, req->out.allocated);
218 smb_panic("out of memory in req_grow_allocation");
221 if (buf2 == req->out.buffer) {
222 /* the malloc library gave us the same pointer */
226 /* update the pointers into the packet */
227 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
228 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
229 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
230 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
232 req->out.buffer = buf2;
237 grow the data buffer portion of a reply packet. Note that as this
238 can reallocate the packet buffer this invalidates any local pointers
241 To cope with this req->out.ptr is supplied. This will be updated to
242 point at the same offset into the packet as before this call
244 void smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
248 smbcli_req_grow_allocation(req, new_size);
250 delta = new_size - req->out.data_size;
252 req->out.size += delta;
253 req->out.data_size += delta;
255 /* set the BCC to the new data size */
256 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
263 BOOL smbcli_request_send(struct smbcli_request *req)
265 if (IVAL(req->out.buffer, 0) == 0) {
266 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
269 smbcli_request_calculate_sign_mac(req);
271 smbcli_transport_send(req);
278 receive a response to a packet
280 BOOL smbcli_request_receive(struct smbcli_request *req)
282 /* req can be NULL when a send has failed. This eliminates lots of NULL
283 checks in each module */
284 if (!req) return False;
286 /* keep receiving packets until this one is replied to */
287 while (req->state <= SMBCLI_REQUEST_RECV) {
288 event_loop_once(req->transport->event.ctx);
291 return req->state == SMBCLI_REQUEST_DONE;
296 receive another reply to a request - this is used for requests that
297 have multi-part replies (such as SMBtrans2)
299 BOOL smbcli_request_receive_more(struct smbcli_request *req)
301 req->state = SMBCLI_REQUEST_RECV;
302 DLIST_ADD(req->transport->pending_recv, req);
304 return smbcli_request_receive(req);
309 handle oplock break requests from the server - return True if the request was
312 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const char *hdr, const char *vwv)
314 /* we must be very fussy about what we consider an oplock break to avoid
315 matching readbraw replies */
316 if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
317 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
318 CVAL(hdr,HDR_COM) != SMBlockingX ||
319 SVAL(hdr, HDR_MID) != 0xFFFF ||
320 SVAL(vwv,VWV(6)) != 0 ||
321 SVAL(vwv,VWV(7)) != 0) {
325 if (transport->oplock.handler) {
326 uint16_t tid = SVAL(hdr, HDR_TID);
327 uint16_t fnum = SVAL(vwv,VWV(2));
328 uint8_t level = CVAL(vwv,VWV(3)+1);
329 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
336 wait for a reply to be received for a packet that just returns an error
337 code and nothing more
339 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
341 smbcli_request_receive(req);
342 return smbcli_request_destroy(req);
346 /* Return true if the last packet was in error */
347 BOOL smbcli_request_is_error(struct smbcli_request *req)
349 return NT_STATUS_IS_ERR(req->status);
353 append a string into the data portion of the request packet
355 return the number of bytes added to the packet
357 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
361 /* determine string type to use */
362 if (!(flags & (STR_ASCII|STR_UNICODE))) {
363 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
366 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
368 smbcli_req_grow_allocation(req, len + req->out.data_size);
370 len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
372 smbcli_req_grow_data(req, len + req->out.data_size);
378 this is like smbcli_req_append_string but it also return the
379 non-terminated string byte length, which can be less than the number
380 of bytes consumed in the packet for 2 reasons:
382 1) the string in the packet may be null terminated
383 2) the string in the packet may need a 1 byte UCS2 alignment
385 this is used in places where the non-terminated string byte length is
386 placed in the packet as a separate field
388 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
393 /* determine string type to use */
394 if (!(flags & (STR_ASCII|STR_UNICODE))) {
395 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
398 /* see if an alignment byte will be used */
399 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
400 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
403 /* do the hard work */
404 ret = smbcli_req_append_string(req, str, flags);
406 /* see if we need to subtract the termination */
407 if (flags & STR_TERMINATE) {
408 diff += (flags & STR_UNICODE) ? 2 : 1;
422 push a string into the data portion of the request packet, growing it if necessary
423 this gets quite tricky - please be very careful to cover all cases when modifying this
425 if dest is NULL, then put the string at the end of the data portion of the packet
427 if dest_len is -1 then no limit applies
429 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
432 smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
433 size = smbcli_req_append_string(req, str, flags);
439 push a blob into the data portion of the request packet, growing it if necessary
440 this gets quite tricky - please be very careful to cover all cases when modifying this
442 if dest is NULL, then put the blob at the end of the data portion of the packet
444 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
446 smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
447 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
448 smbcli_req_grow_data(req, req->out.data_size + blob->length);
453 append raw bytes into the data portion of the request packet
454 return the number of bytes added
456 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
458 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
459 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
460 smbcli_req_grow_data(req, byte_len + req->out.data_size);
465 append variable block (type 5 buffer) into the data portion of the request packet
466 return the number of bytes added
468 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
470 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
471 SCVAL(req->out.data + req->out.data_size, 0, 5);
472 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
474 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
476 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
482 pull a UCS2 string from a request packet, returning a talloced unix string
484 the string length is limited by the 3 things:
485 - the data size in the request (end of packet)
486 - the passed 'byte_len' if it is not -1
487 - the end of string (null termination)
489 Note that 'byte_len' is the number of bytes in the packet
491 on failure zero is returned and *dest is set to NULL, otherwise the number
492 of bytes consumed in the packet is returned
494 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
495 char **dest, const char *src, int byte_len, uint_t flags)
497 int src_len, src_len2, alignment=0;
500 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
503 if (byte_len != -1) {
508 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
513 if (byte_len != -1 && src_len > byte_len) {
517 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
518 if (src_len2 < src_len - 2) {
519 /* include the termination if we didn't reach the end of the packet */
523 /* ucs2 strings must be at least 2 bytes long */
529 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
535 return src_len2 + alignment;
539 pull a ascii string from a request packet, returning a talloced string
541 the string length is limited by the 3 things:
542 - the data size in the request (end of packet)
543 - the passed 'byte_len' if it is not -1
544 - the end of string (null termination)
546 Note that 'byte_len' is the number of bytes in the packet
548 on failure zero is returned and *dest is set to NULL, otherwise the number
549 of bytes consumed in the packet is returned
551 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
552 char **dest, const char *src, int byte_len, uint_t flags)
554 int src_len, src_len2;
557 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
562 if (byte_len != -1 && src_len > byte_len) {
565 src_len2 = strnlen(src, src_len);
566 if (src_len2 < src_len - 1) {
567 /* include the termination if we didn't reach the end of the packet */
571 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
582 pull a string from a request packet, returning a talloced string
584 the string length is limited by the 3 things:
585 - the data size in the request (end of packet)
586 - the passed 'byte_len' if it is not -1
587 - the end of string (null termination)
589 Note that 'byte_len' is the number of bytes in the packet
591 on failure zero is returned and *dest is set to NULL, otherwise the number
592 of bytes consumed in the packet is returned
594 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
595 char **dest, const char *src, int byte_len, uint_t flags)
597 if (!(flags & STR_ASCII) &&
598 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
599 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
602 return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
607 pull a DATA_BLOB from a reply packet, returning a talloced blob
608 make sure we don't go past end of packet
610 if byte_len is -1 then limit the blob only by packet size
612 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
616 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
619 return data_blob(NULL, 0);
622 if (byte_len != -1 && src_len > byte_len) {
626 return data_blob_talloc(mem_ctx, src, src_len);
629 /* check that a lump of data in a request is within the bounds of the data section of
631 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const char *ptr, uint32_t count)
633 /* be careful with wraparound! */
634 if (ptr < req->in.data ||
635 ptr >= req->in.data + req->in.data_size ||
636 count > req->in.data_size ||
637 ptr + count > req->in.data + req->in.data_size) {
644 pull a lump of data from a request packet
646 return False if any part is outside the data portion of the packet
648 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const char *src, int len, char *dest)
650 if (len == 0) return True;
652 if (smbcli_req_data_oob(req, src, len)) {
656 memcpy(dest, src, len);
662 put a NTTIME into a packet
664 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
666 SBVAL(base, offset, t);
670 pull a NTTIME from a packet
672 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
674 NTTIME ret = BVAL(base, offset);
679 pull a UCS2 string from a blob, returning a talloced unix string
681 the string length is limited by the 3 things:
682 - the data size in the blob
683 - the passed 'byte_len' if it is not -1
684 - the end of string (null termination)
686 Note that 'byte_len' is the number of bytes in the packet
688 on failure zero is returned and *dest is set to NULL, otherwise the number
689 of bytes consumed in the blob is returned
691 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
692 DATA_BLOB *blob, const char **dest,
693 const char *src, int byte_len, uint_t flags)
695 int src_len, src_len2, alignment=0;
698 if (src < (const char *)blob->data ||
699 src >= (const char *)(blob->data + blob->length)) {
704 src_len = blob->length - PTR_DIFF(src, blob->data);
706 if (byte_len != -1 && src_len > byte_len) {
710 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
721 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
723 if (src_len2 < src_len - 2) {
724 /* include the termination if we didn't reach the end of the packet */
728 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
734 return src_len2 + alignment;
738 pull a ascii string from a blob, returning a talloced string
740 the string length is limited by the 3 things:
741 - the data size in the blob
742 - the passed 'byte_len' if it is not -1
743 - the end of string (null termination)
745 Note that 'byte_len' is the number of bytes in the blob
747 on failure zero is returned and *dest is set to NULL, otherwise the number
748 of bytes consumed in the blob is returned
750 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
751 DATA_BLOB *blob, const char **dest,
752 const char *src, int byte_len, uint_t flags)
754 int src_len, src_len2;
757 src_len = blob->length - PTR_DIFF(src, blob->data);
762 if (byte_len != -1 && src_len > byte_len) {
765 src_len2 = strnlen(src, src_len);
767 if (src_len2 < src_len - 1) {
768 /* include the termination if we didn't reach the end of the packet */
772 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
783 pull a string from a blob, returning a talloced WIRE_STRING
785 the string length is limited by the 3 things:
786 - the data size in the blob
787 - length field on the wire
788 - the end of string (null termination)
790 if STR_LEN8BIT is set in the flags then assume the length field is
791 8 bits, instead of 32
793 on failure zero is returned and dest->s is set to NULL, otherwise the number
794 of bytes consumed in the blob is returned
796 size_t smbcli_blob_pull_string(struct smbcli_session *session,
800 uint16_t len_offset, uint16_t str_offset,
806 if (flags & STR_LEN8BIT) {
807 if (len_offset > blob->length-1) {
810 dest->private_length = CVAL(blob->data, len_offset);
812 if (len_offset > blob->length-4) {
815 dest->private_length = IVAL(blob->data, len_offset);
819 if (!(flags & STR_ASCII) &&
820 ((flags & STR_UNICODE) ||
821 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
823 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
826 if (flags & STR_LEN_NOTERM) {
829 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
830 blob->data+str_offset+align,
831 dest->private_length, flags);
834 if (flags & STR_LEN_NOTERM) {
838 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
839 blob->data+str_offset, dest->private_length, flags);
843 pull a string from a blob, returning a talloced char *
845 Currently only used by the UNIX search info level.
847 the string length is limited by 2 things:
848 - the data size in the blob
849 - the end of string (null termination)
851 on failure zero is returned and dest->s is set to NULL, otherwise the number
852 of bytes consumed in the blob is returned
854 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
864 if (!(flags & STR_ASCII) &&
865 ((flags & STR_UNICODE) ||
866 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
868 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
871 if (flags & STR_LEN_NOTERM) {
874 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
875 blob->data+str_offset+align,
879 if (flags & STR_LEN_NOTERM) {
883 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
884 blob->data+str_offset, -1, flags);
889 append a string into a blob
891 size_t smbcli_blob_append_string(struct smbcli_session *session,
892 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
893 const char *str, uint_t flags)
900 /* determine string type to use */
901 if (!(flags & (STR_ASCII|STR_UNICODE))) {
902 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
905 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
907 blob->data = talloc_realloc(blob->data, blob->length + max_len);
912 len = push_string(NULL, blob->data + blob->length, str, max_len, flags);