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"
28 #include "dlinklist.h"
30 /* we over allocate the data buffer to prevent too many realloc calls */
31 #define REQ_OVER_ALLOCATION 0
33 /* assume that a character will not consume more than 3 bytes per char */
34 #define MAX_BYTES_PER_CHAR 3
36 /* destroy a request structure and return final status */
37 NTSTATUS smbcli_request_destroy(struct smbcli_request *req)
41 /* this is the error code we give the application for when a
42 _send() call fails completely */
43 if (!req) return NT_STATUS_UNSUCCESSFUL;
46 /* remove it from the list of pending requests (a null op if
47 its not in the list) */
48 DLIST_REMOVE(req->transport->pending_recv, req);
51 if (req->state == SMBCLI_REQUEST_ERROR &&
52 NT_STATUS_IS_OK(req->status)) {
53 req->status = NT_STATUS_INTERNAL_ERROR;
63 low-level function to setup a request buffer for a non-SMB packet
64 at the transport level
66 struct smbcli_request *smbcli_request_setup_nonsmb(struct smbcli_transport *transport, uint_t size)
68 struct smbcli_request *req;
70 req = talloc_p(transport, struct smbcli_request);
76 /* setup the request context */
77 req->state = SMBCLI_REQUEST_INIT;
78 req->transport = transport;
83 /* over allocate by a small amount */
84 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
86 req->out.buffer = talloc(req, req->out.allocated);
87 if (!req->out.buffer) {
91 SIVAL(req->out.buffer, 0, 0);
98 setup a SMB packet at transport level
100 struct smbcli_request *smbcli_request_setup_transport(struct smbcli_transport *transport,
101 uint8_t command, uint_t wct, uint_t buflen)
103 struct smbcli_request *req;
105 req = smbcli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
107 if (!req) return NULL;
109 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
110 req->out.vwv = req->out.hdr + HDR_VWV;
112 req->out.data = req->out.vwv + VWV(wct) + 2;
113 req->out.data_size = buflen;
114 req->out.ptr = req->out.data;
116 SCVAL(req->out.hdr, HDR_WCT, wct);
117 SSVAL(req->out.vwv, VWV(wct), buflen);
119 memcpy(req->out.hdr, "\377SMB", 4);
120 SCVAL(req->out.hdr,HDR_COM,command);
122 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
123 SSVAL(req->out.hdr,HDR_FLG2, 0);
125 if (command != SMBtranss && command != SMBtranss2) {
127 req->mid = smbcli_transport_next_mid(transport);
130 /* copy the pid, uid and mid to the request */
131 SSVAL(req->out.hdr, HDR_PID, 0);
132 SSVAL(req->out.hdr, HDR_UID, 0);
133 SSVAL(req->out.hdr, HDR_MID, req->mid);
134 SSVAL(req->out.hdr, HDR_TID,0);
135 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
136 SIVAL(req->out.hdr, HDR_RCLS, 0);
137 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
143 setup a reply in req->out with the given word count and initial data
144 buffer size. the caller will then fill in the command words and
145 data before calling smbcli_request_send() to send the reply on its
146 way. This interface is used before a session is setup.
148 struct smbcli_request *smbcli_request_setup_session(struct smbcli_session *session,
149 uint8_t command, uint_t wct, uint_t buflen)
151 struct smbcli_request *req;
153 req = smbcli_request_setup_transport(session->transport, command, wct, buflen);
155 if (!req) return NULL;
157 req->session = session;
159 SSVAL(req->out.hdr, HDR_FLG2, session->flags2);
160 SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
161 SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
162 SSVAL(req->out.hdr, HDR_UID, session->vuid);
168 setup a request for tree based commands
170 struct smbcli_request *smbcli_request_setup(struct smbcli_tree *tree,
172 uint_t wct, uint_t buflen)
174 struct smbcli_request *req;
176 req = smbcli_request_setup_session(tree->session, command, wct, buflen);
179 SSVAL(req->out.hdr,HDR_TID,tree->tid);
185 grow the allocation of the data buffer portion of a reply
186 packet. Note that as this can reallocate the packet buffer this
187 invalidates any local pointers into the packet.
189 To cope with this req->out.ptr is supplied. This will be updated to
190 point at the same offset into the packet as before this call
192 static void smbcli_req_grow_allocation(struct smbcli_request *req, uint_t new_size)
197 delta = new_size - req->out.data_size;
198 if (delta + req->out.size <= req->out.allocated) {
199 /* it fits in the preallocation */
203 /* we need to realloc */
204 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
205 buf2 = talloc_realloc(req, req->out.buffer, req->out.allocated);
207 smb_panic("out of memory in req_grow_allocation");
210 if (buf2 == req->out.buffer) {
211 /* the malloc library gave us the same pointer */
215 /* update the pointers into the packet */
216 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
217 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
218 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
219 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
221 req->out.buffer = buf2;
226 grow the data buffer portion of a reply packet. Note that as this
227 can reallocate the packet buffer this invalidates any local pointers
230 To cope with this req->out.ptr is supplied. This will be updated to
231 point at the same offset into the packet as before this call
233 static void smbcli_req_grow_data(struct smbcli_request *req, uint_t new_size)
237 smbcli_req_grow_allocation(req, new_size);
239 delta = new_size - req->out.data_size;
241 req->out.size += delta;
242 req->out.data_size += delta;
244 /* set the BCC to the new data size */
245 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
252 BOOL smbcli_request_send(struct smbcli_request *req)
254 if (IVAL(req->out.buffer, 0) == 0) {
255 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
258 smbcli_request_calculate_sign_mac(req);
260 smbcli_transport_send(req);
267 receive a response to a packet
269 BOOL smbcli_request_receive(struct smbcli_request *req)
271 /* req can be NULL when a send has failed. This eliminates lots of NULL
272 checks in each module */
273 if (!req) return False;
275 /* keep receiving packets until this one is replied to */
276 while (req->state <= SMBCLI_REQUEST_RECV) {
277 if (event_loop_once(req->transport->event.ctx) != 0) {
282 return req->state == SMBCLI_REQUEST_DONE;
287 receive another reply to a request - this is used for requests that
288 have multi-part replies (such as SMBtrans2)
290 BOOL smbcli_request_receive_more(struct smbcli_request *req)
292 req->state = SMBCLI_REQUEST_RECV;
293 DLIST_ADD(req->transport->pending_recv, req);
295 return smbcli_request_receive(req);
300 handle oplock break requests from the server - return True if the request was
303 BOOL handle_oplock_break(struct smbcli_transport *transport, uint_t len, const uint8_t *hdr, const uint8_t *vwv)
305 /* we must be very fussy about what we consider an oplock break to avoid
306 matching readbraw replies */
307 if (len != MIN_SMB_SIZE + VWV(8) + NBT_HDR_SIZE ||
308 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
309 CVAL(hdr,HDR_COM) != SMBlockingX ||
310 SVAL(hdr, HDR_MID) != 0xFFFF ||
311 SVAL(vwv,VWV(6)) != 0 ||
312 SVAL(vwv,VWV(7)) != 0) {
316 if (transport->oplock.handler) {
317 uint16_t tid = SVAL(hdr, HDR_TID);
318 uint16_t fnum = SVAL(vwv,VWV(2));
319 uint8_t level = CVAL(vwv,VWV(3)+1);
320 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
327 wait for a reply to be received for a packet that just returns an error
328 code and nothing more
330 NTSTATUS smbcli_request_simple_recv(struct smbcli_request *req)
332 smbcli_request_receive(req);
333 return smbcli_request_destroy(req);
337 /* Return true if the last packet was in error */
338 BOOL smbcli_request_is_error(struct smbcli_request *req)
340 return NT_STATUS_IS_ERR(req->status);
344 append a string into the data portion of the request packet
346 return the number of bytes added to the packet
348 size_t smbcli_req_append_string(struct smbcli_request *req, const char *str, uint_t flags)
352 /* determine string type to use */
353 if (!(flags & (STR_ASCII|STR_UNICODE))) {
354 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
357 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
359 smbcli_req_grow_allocation(req, len + req->out.data_size);
361 len = push_string(req->out.data + req->out.data_size, str, len, flags);
363 smbcli_req_grow_data(req, len + req->out.data_size);
370 this is like smbcli_req_append_string but it also return the
371 non-terminated string byte length, which can be less than the number
372 of bytes consumed in the packet for 2 reasons:
374 1) the string in the packet may be null terminated
375 2) the string in the packet may need a 1 byte UCS2 alignment
377 this is used in places where the non-terminated string byte length is
378 placed in the packet as a separate field
380 size_t smbcli_req_append_string_len(struct smbcli_request *req, const char *str, uint_t flags, int *len)
385 /* determine string type to use */
386 if (!(flags & (STR_ASCII|STR_UNICODE))) {
387 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
390 /* see if an alignment byte will be used */
391 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
392 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
395 /* do the hard work */
396 ret = smbcli_req_append_string(req, str, flags);
398 /* see if we need to subtract the termination */
399 if (flags & STR_TERMINATE) {
400 diff += (flags & STR_UNICODE) ? 2 : 1;
414 push a string into the data portion of the request packet, growing it if necessary
415 this gets quite tricky - please be very careful to cover all cases when modifying this
417 if dest is NULL, then put the string at the end of the data portion of the packet
419 if dest_len is -1 then no limit applies
421 size_t smbcli_req_append_ascii4(struct smbcli_request *req, const char *str, uint_t flags)
424 smbcli_req_append_bytes(req, (const uint8_t *)"\4", 1);
425 size = smbcli_req_append_string(req, str, flags);
431 push a blob into the data portion of the request packet, growing it if necessary
432 this gets quite tricky - please be very careful to cover all cases when modifying this
434 if dest is NULL, then put the blob at the end of the data portion of the packet
436 size_t smbcli_req_append_blob(struct smbcli_request *req, const DATA_BLOB *blob)
438 smbcli_req_grow_allocation(req, req->out.data_size + blob->length);
439 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
440 smbcli_req_grow_data(req, req->out.data_size + blob->length);
445 append raw bytes into the data portion of the request packet
446 return the number of bytes added
448 size_t smbcli_req_append_bytes(struct smbcli_request *req, const uint8_t *bytes, size_t byte_len)
450 smbcli_req_grow_allocation(req, byte_len + req->out.data_size);
451 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
452 smbcli_req_grow_data(req, byte_len + req->out.data_size);
457 append variable block (type 5 buffer) into the data portion of the request packet
458 return the number of bytes added
460 size_t smbcli_req_append_var_block(struct smbcli_request *req, const uint8_t *bytes, uint16_t byte_len)
462 smbcli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
463 SCVAL(req->out.data + req->out.data_size, 0, 5);
464 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
466 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
468 smbcli_req_grow_data(req, byte_len + 3 + req->out.data_size);
474 pull a UCS2 string from a request packet, returning a talloced unix string
476 the string length is limited by the 3 things:
477 - the data size in the request (end of packet)
478 - the passed 'byte_len' if it is not -1
479 - the end of string (null termination)
481 Note that 'byte_len' is the number of bytes in the packet
483 on failure zero is returned and *dest is set to NULL, otherwise the number
484 of bytes consumed in the packet is returned
486 static size_t smbcli_req_pull_ucs2(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
487 char **dest, const uint8_t *src, int byte_len, uint_t flags)
489 int src_len, src_len2, alignment=0;
492 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
495 if (byte_len != -1) {
500 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
505 if (byte_len != -1 && src_len > byte_len) {
509 src_len2 = utf16_len_n(src, src_len);
511 /* ucs2 strings must be at least 2 bytes long */
517 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)dest);
523 return src_len2 + alignment;
527 pull a ascii string from a request packet, returning a talloced string
529 the string length is limited by the 3 things:
530 - the data size in the request (end of packet)
531 - the passed 'byte_len' if it is not -1
532 - the end of string (null termination)
534 Note that 'byte_len' is the number of bytes in the packet
536 on failure zero is returned and *dest is set to NULL, otherwise the number
537 of bytes consumed in the packet is returned
539 size_t smbcli_req_pull_ascii(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
540 char **dest, const uint8_t *src, int byte_len, uint_t flags)
542 int src_len, src_len2;
545 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
550 if (byte_len != -1 && src_len > byte_len) {
553 src_len2 = strnlen((const char *)src, src_len);
554 if (src_len2 < src_len - 1) {
555 /* include the termination if we didn't reach the end of the packet */
559 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)dest);
570 pull a string from a request packet, returning a talloced string
572 the string length is limited by the 3 things:
573 - the data size in the request (end of packet)
574 - the passed 'byte_len' if it is not -1
575 - the end of string (null termination)
577 Note that 'byte_len' is the number of bytes in the packet
579 on failure zero is returned and *dest is set to NULL, otherwise the number
580 of bytes consumed in the packet is returned
582 size_t smbcli_req_pull_string(struct smbcli_request *req, TALLOC_CTX *mem_ctx,
583 char **dest, const uint8_t *src, int byte_len, uint_t flags)
585 if (!(flags & STR_ASCII) &&
586 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
587 return smbcli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
590 return smbcli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
595 pull a DATA_BLOB from a reply packet, returning a talloced blob
596 make sure we don't go past end of packet
598 if byte_len is -1 then limit the blob only by packet size
600 DATA_BLOB smbcli_req_pull_blob(struct smbcli_request *req, TALLOC_CTX *mem_ctx, const uint8_t *src, int byte_len)
604 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
607 return data_blob(NULL, 0);
610 if (byte_len != -1 && src_len > byte_len) {
614 return data_blob_talloc(mem_ctx, src, src_len);
617 /* check that a lump of data in a request is within the bounds of the data section of
619 static BOOL smbcli_req_data_oob(struct smbcli_request *req, const uint8_t *ptr, uint32_t count)
621 /* be careful with wraparound! */
622 if (ptr < req->in.data ||
623 ptr >= req->in.data + req->in.data_size ||
624 count > req->in.data_size ||
625 ptr + count > req->in.data + req->in.data_size) {
632 pull a lump of data from a request packet
634 return False if any part is outside the data portion of the packet
636 BOOL smbcli_raw_pull_data(struct smbcli_request *req, const uint8_t *src, int len, uint8_t *dest)
638 if (len == 0) return True;
640 if (smbcli_req_data_oob(req, src, len)) {
644 memcpy(dest, src, len);
650 put a NTTIME into a packet
652 void smbcli_push_nttime(void *base, uint16_t offset, NTTIME t)
654 SBVAL(base, offset, t);
658 pull a NTTIME from a packet
660 NTTIME smbcli_pull_nttime(void *base, uint16_t offset)
662 NTTIME ret = BVAL(base, offset);
667 pull a UCS2 string from a blob, returning a talloced unix string
669 the string length is limited by the 3 things:
670 - the data size in the blob
671 - the passed 'byte_len' if it is not -1
672 - the end of string (null termination)
674 Note that 'byte_len' is the number of bytes in the packet
676 on failure zero is returned and *dest is set to NULL, otherwise the number
677 of bytes consumed in the blob is returned
679 static size_t smbcli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
680 DATA_BLOB *blob, const char **dest,
681 const uint8_t *src, int byte_len, uint_t flags)
683 int src_len, src_len2, alignment=0;
687 if (src < blob->data ||
688 src >= (blob->data + blob->length)) {
693 src_len = blob->length - PTR_DIFF(src, blob->data);
695 if (byte_len != -1 && src_len > byte_len) {
699 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
710 src_len2 = utf16_len_n(src, src_len);
712 ret = convert_string_talloc(mem_ctx, CH_UTF16, CH_UNIX, src, src_len2, (void **)&dest2);
719 return src_len2 + alignment;
723 pull a ascii string from a blob, returning a talloced string
725 the string length is limited by the 3 things:
726 - the data size in the blob
727 - the passed 'byte_len' if it is not -1
728 - the end of string (null termination)
730 Note that 'byte_len' is the number of bytes in the blob
732 on failure zero is returned and *dest is set to NULL, otherwise the number
733 of bytes consumed in the blob is returned
735 static size_t smbcli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
736 DATA_BLOB *blob, const char **dest,
737 const uint8_t *src, int byte_len, uint_t flags)
739 int src_len, src_len2;
743 src_len = blob->length - PTR_DIFF(src, blob->data);
748 if (byte_len != -1 && src_len > byte_len) {
751 src_len2 = strnlen((const char *)src, src_len);
753 if (src_len2 < src_len - 1) {
754 /* include the termination if we didn't reach the end of the packet */
758 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (void **)&dest2);
770 pull a string from a blob, returning a talloced WIRE_STRING
772 the string length is limited by the 3 things:
773 - the data size in the blob
774 - length field on the wire
775 - the end of string (null termination)
777 if STR_LEN8BIT is set in the flags then assume the length field is
778 8 bits, instead of 32
780 on failure zero is returned and dest->s is set to NULL, otherwise the number
781 of bytes consumed in the blob is returned
783 size_t smbcli_blob_pull_string(struct smbcli_session *session,
787 uint16_t len_offset, uint16_t str_offset,
793 if (flags & STR_LEN8BIT) {
794 if (len_offset > blob->length-1) {
797 dest->private_length = CVAL(blob->data, len_offset);
799 if (len_offset > blob->length-4) {
802 dest->private_length = IVAL(blob->data, len_offset);
806 if (!(flags & STR_ASCII) &&
807 ((flags & STR_UNICODE) ||
808 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
810 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
813 if (flags & STR_LEN_NOTERM) {
816 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
817 blob->data+str_offset+align,
818 dest->private_length, flags);
821 if (flags & STR_LEN_NOTERM) {
825 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, &dest->s,
826 blob->data+str_offset, dest->private_length, flags);
830 pull a string from a blob, returning a talloced char *
832 Currently only used by the UNIX search info level.
834 the string length is limited by 2 things:
835 - the data size in the blob
836 - the end of string (null termination)
838 on failure zero is returned and dest->s is set to NULL, otherwise the number
839 of bytes consumed in the blob is returned
841 size_t smbcli_blob_pull_unix_string(struct smbcli_session *session,
851 if (!(flags & STR_ASCII) &&
852 ((flags & STR_UNICODE) ||
853 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
855 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
858 if (flags & STR_LEN_NOTERM) {
861 return align + extra + smbcli_blob_pull_ucs2(mem_ctx, blob, dest,
862 blob->data+str_offset+align,
866 if (flags & STR_LEN_NOTERM) {
870 return extra + smbcli_blob_pull_ascii(mem_ctx, blob, dest,
871 blob->data+str_offset, -1, flags);
876 append a string into a blob
878 size_t smbcli_blob_append_string(struct smbcli_session *session,
879 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
880 const char *str, uint_t flags)
887 /* determine string type to use */
888 if (!(flags & (STR_ASCII|STR_UNICODE))) {
889 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
892 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
894 blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
899 len = push_string(blob->data + blob->length, str, max_len, flags);