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_p(transport, struct smbcli_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, 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 if (event_loop_once(req->transport->event.ctx) != 0) {
293 return req->state == SMBCLI_REQUEST_DONE;
298 receive another reply to a request - this is used for requests that
299 have multi-part replies (such as SMBtrans2)
301 BOOL smbcli_request_receive_more(struct smbcli_request *req)
303 req->state = SMBCLI_REQUEST_RECV;
304 DLIST_ADD(req->transport->pending_recv, req);
306 return smbcli_request_receive(req);
311 handle oplock break requests from the server - return True if the request was
314 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const char *hdr, const char *vwv)
316 /* we must be very fussy about what we consider an oplock break to avoid
317 matching readbraw replies */
318 if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
319 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
320 CVAL(hdr,HDR_COM) != SMBlockingX ||
321 SVAL(hdr, HDR_MID) != 0xFFFF ||
322 SVAL(vwv,VWV(6)) != 0 ||
323 SVAL(vwv,VWV(7)) != 0) {
327 if (transport->oplock.handler) {
328 uint16_t tid = SVAL(hdr, HDR_TID);
329 uint16_t fnum = SVAL(vwv,VWV(2));
330 uint8_t level = CVAL(vwv,VWV(3)+1);
331 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
338 wait for a reply to be received for a packet that just returns an error
339 code and nothing more
341 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
343 smbcli_request_receive(req);
344 return smbcli_request_destroy(req);
348 /* Return true if the last packet was in error */
349 BOOL smbcli_request_is_error(struct smbcli_request *req)
351 return NT_STATUS_IS_ERR(req->status);
355 append a string into the data portion of the request packet
357 return the number of bytes added to the packet
359 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
363 /* determine string type to use */
364 if (!(flags & (STR_ASCII|STR_UNICODE))) {
365 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
368 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
370 smbcli_req_grow_allocation(req, len + req->out.data_size);
372 len = push_string(req->out.data + req->out.data_size, str, len, flags);
374 smbcli_req_grow_data(req, len + req->out.data_size);
381 this is like smbcli_req_append_string but it also return the
382 non-terminated string byte length, which can be less than the number
383 of bytes consumed in the packet for 2 reasons:
385 1) the string in the packet may be null terminated
386 2) the string in the packet may need a 1 byte UCS2 alignment
388 this is used in places where the non-terminated string byte length is
389 placed in the packet as a separate field
391 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
396 /* determine string type to use */
397 if (!(flags & (STR_ASCII|STR_UNICODE))) {
398 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
401 /* see if an alignment byte will be used */
402 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
403 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
406 /* do the hard work */
407 ret = smbcli_req_append_string(req, str, flags);
409 /* see if we need to subtract the termination */
410 if (flags & STR_TERMINATE) {
411 diff += (flags & STR_UNICODE) ? 2 : 1;
425 push a string 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 string at the end of the data portion of the packet
430 if dest_len is -1 then no limit applies
432 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
435 smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
436 size = smbcli_req_append_string(req, str, flags);
442 push a blob into the data portion of the request packet, growing it if necessary
443 this gets quite tricky - please be very careful to cover all cases when modifying this
445 if dest is NULL, then put the blob at the end of the data portion of the packet
447 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
449 smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
450 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
451 smbcli_req_grow_data(req, req->out.data_size + blob->length);
456 append raw bytes into the data portion of the request packet
457 return the number of bytes added
459 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
461 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
462 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
463 smbcli_req_grow_data(req, byte_len + req->out.data_size);
468 append variable block (type 5 buffer) into the data portion of the request packet
469 return the number of bytes added
471 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
473 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
474 SCVAL(req->out.data + req->out.data_size, 0, 5);
475 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
477 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
479 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
485 pull a UCS2 string from a request packet, returning a talloced unix string
487 the string length is limited by the 3 things:
488 - the data size in the request (end of packet)
489 - the passed 'byte_len' if it is not -1
490 - the end of string (null termination)
492 Note that 'byte_len' is the number of bytes in the packet
494 on failure zero is returned and *dest is set to NULL, otherwise the number
495 of bytes consumed in the packet is returned
497 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
498 char **dest, const char *src, int byte_len, uint_t flags)
500 int src_len, src_len2, alignment=0;
503 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
506 if (byte_len != -1) {
511 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
516 if (byte_len != -1 && src_len > byte_len) {
520 src_len2 = utf16_len_n(src, src_len);
522 /* ucs2 strings must be at least 2 bytes long */
528 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest);
534 return src_len2 + alignment;
538 pull a ascii string from a request packet, returning a talloced string
540 the string length is limited by the 3 things:
541 - the data size in the request (end of packet)
542 - the passed 'byte_len' if it is not -1
543 - the end of string (null termination)
545 Note that 'byte_len' is the number of bytes in the packet
547 on failure zero is returned and *dest is set to NULL, otherwise the number
548 of bytes consumed in the packet is returned
550 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
551 char **dest, const char *src, int byte_len, uint_t flags)
553 int src_len, src_len2;
556 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
561 if (byte_len != -1 && src_len > byte_len) {
564 src_len2 = strnlen(src, src_len);
565 if (src_len2 < src_len - 1) {
566 /* include the termination if we didn't reach the end of the packet */
570 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest);
581 pull a string from a request packet, returning a talloced string
583 the string length is limited by the 3 things:
584 - the data size in the request (end of packet)
585 - the passed 'byte_len' if it is not -1
586 - the end of string (null termination)
588 Note that 'byte_len' is the number of bytes in the packet
590 on failure zero is returned and *dest is set to NULL, otherwise the number
591 of bytes consumed in the packet is returned
593 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
594 char **dest, const char *src, int byte_len, uint_t flags)
596 if (!(flags & STR_ASCII) &&
597 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
598 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
601 return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
606 pull a DATA_BLOB from a reply packet, returning a talloced blob
607 make sure we don't go past end of packet
609 if byte_len is -1 then limit the blob only by packet size
611 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
615 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
618 return data_blob(NULL, 0);
621 if (byte_len != -1 && src_len > byte_len) {
625 return data_blob_talloc(mem_ctx, src, src_len);
628 /* check that a lump of data in a request is within the bounds of the data section of
630 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const char *ptr, uint32_t count)
632 /* be careful with wraparound! */
633 if (ptr < req->in.data ||
634 ptr >= req->in.data + req->in.data_size ||
635 count > req->in.data_size ||
636 ptr + count > req->in.data + req->in.data_size) {
643 pull a lump of data from a request packet
645 return False if any part is outside the data portion of the packet
647 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const char *src, int len, char *dest)
649 if (len == 0) return True;
651 if (smbcli_req_data_oob(req, src, len)) {
655 memcpy(dest, src, len);
661 put a NTTIME into a packet
663 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
665 SBVAL(base, offset, t);
669 pull a NTTIME from a packet
671 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
673 NTTIME ret = BVAL(base, offset);
678 pull a UCS2 string from a blob, returning a talloced unix string
680 the string length is limited by the 3 things:
681 - the data size in the blob
682 - the passed 'byte_len' if it is not -1
683 - the end of string (null termination)
685 Note that 'byte_len' is the number of bytes in the packet
687 on failure zero is returned and *dest is set to NULL, otherwise the number
688 of bytes consumed in the blob is returned
690 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
691 DATA_BLOB *blob, const char **dest,
692 const char *src, int byte_len, uint_t flags)
694 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 = utf16_len_n(src, src_len);
723 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
730 return src_len2 + alignment;
734 pull a ascii string from a blob, returning a talloced string
736 the string length is limited by the 3 things:
737 - the data size in the blob
738 - the passed 'byte_len' if it is not -1
739 - the end of string (null termination)
741 Note that 'byte_len' is the number of bytes in the blob
743 on failure zero is returned and *dest is set to NULL, otherwise the number
744 of bytes consumed in the blob is returned
746 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
747 DATA_BLOB *blob, const char **dest,
748 const char *src, int byte_len, uint_t flags)
750 int src_len, src_len2;
754 src_len = blob->length - PTR_DIFF(src, blob->data);
759 if (byte_len != -1 && src_len > byte_len) {
762 src_len2 = strnlen(src, src_len);
764 if (src_len2 < src_len - 1) {
765 /* include the termination if we didn't reach the end of the packet */
769 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
781 pull a string from a blob, returning a talloced WIRE_STRING
783 the string length is limited by the 3 things:
784 - the data size in the blob
785 - length field on the wire
786 - the end of string (null termination)
788 if STR_LEN8BIT is set in the flags then assume the length field is
789 8 bits, instead of 32
791 on failure zero is returned and dest->s is set to NULL, otherwise the number
792 of bytes consumed in the blob is returned
794 size_t smbcli_blob_pull_string(struct smbcli_session *session,
798 uint16_t len_offset, uint16_t str_offset,
804 if (flags & STR_LEN8BIT) {
805 if (len_offset > blob->length-1) {
808 dest->private_length = CVAL(blob->data, len_offset);
810 if (len_offset > blob->length-4) {
813 dest->private_length = IVAL(blob->data, len_offset);
817 if (!(flags & STR_ASCII) &&
818 ((flags & STR_UNICODE) ||
819 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
821 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
824 if (flags & STR_LEN_NOTERM) {
827 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
828 blob->data+str_offset+align,
829 dest->private_length, flags);
832 if (flags & STR_LEN_NOTERM) {
836 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
837 blob->data+str_offset, dest->private_length, flags);
841 pull a string from a blob, returning a talloced char *
843 Currently only used by the UNIX search info level.
845 the string length is limited by 2 things:
846 - the data size in the blob
847 - the end of string (null termination)
849 on failure zero is returned and dest->s is set to NULL, otherwise the number
850 of bytes consumed in the blob is returned
852 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
862 if (!(flags & STR_ASCII) &&
863 ((flags & STR_UNICODE) ||
864 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
866 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
869 if (flags & STR_LEN_NOTERM) {
872 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
873 blob->data+str_offset+align,
877 if (flags & STR_LEN_NOTERM) {
881 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
882 blob->data+str_offset, -1, flags);
887 append a string into a blob
889 size_t smbcli_blob_append_string(struct smbcli_session *session,
890 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
891 const char *str, uint_t flags)
898 /* determine string type to use */
899 if (!(flags & (STR_ASCII|STR_UNICODE))) {
900 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
903 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
905 blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
910 len = push_string(blob->data + blob->length, str, max_len, flags);