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;
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
52 talloc_destroy(req->mem_ctx);
58 low-level function to setup a request buffer for a non-SMB packet
59 at the transport level
61 struct cli_request *cli_request_setup_nonsmb(struct cli_transport *transport, uint_t size)
63 struct cli_request *req;
66 /* each request gets its own talloc context. The request
67 structure itself is also allocated inside this context,
68 so we need to allocate it before we construct the request
70 mem_ctx = talloc_init("cli_request");
75 req = talloc(mem_ctx, sizeof(struct cli_request));
81 /* setup the request context */
82 req->state = CLI_REQUEST_INIT;
83 req->mem_ctx = mem_ctx;
84 req->transport = transport;
89 /* over allocate by a small amount */
90 req->out.allocated = req->out.size + REQ_OVER_ALLOCATION;
92 req->out.buffer = talloc(req->mem_ctx, req->out.allocated);
93 if (!req->out.buffer) {
97 SIVAL(req->out.buffer, 0, 0);
104 setup a SMB packet at transport level
106 struct cli_request *cli_request_setup_transport(struct cli_transport *transport,
107 uint8_t command, uint_t wct, uint_t buflen)
109 struct cli_request *req;
111 req = cli_request_setup_nonsmb(transport, NBT_HDR_SIZE + MIN_SMB_SIZE + wct*2 + buflen);
113 if (!req) return NULL;
115 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
116 req->out.vwv = req->out.hdr + HDR_VWV;
118 req->out.data = req->out.vwv + VWV(wct) + 2;
119 req->out.data_size = buflen;
120 req->out.ptr = req->out.data;
122 SCVAL(req->out.hdr, HDR_WCT, wct);
123 SSVAL(req->out.vwv, VWV(wct), buflen);
125 memcpy(req->out.hdr, "\377SMB", 4);
126 SCVAL(req->out.hdr,HDR_COM,command);
128 SCVAL(req->out.hdr,HDR_FLG, FLAG_CASELESS_PATHNAMES);
129 SSVAL(req->out.hdr,HDR_FLG2, 0);
132 req->mid = cli_transport_next_mid(transport);
134 /* copy the pid, uid and mid to the request */
135 SSVAL(req->out.hdr, HDR_PID, 0);
136 SSVAL(req->out.hdr, HDR_UID, 0);
137 SSVAL(req->out.hdr, HDR_MID, req->mid);
138 SSVAL(req->out.hdr, HDR_TID,0);
139 SSVAL(req->out.hdr, HDR_PIDHIGH,0);
140 SIVAL(req->out.hdr, HDR_RCLS, 0);
141 memset(req->out.hdr+HDR_SS_FIELD, 0, 10);
147 setup a reply in req->out with the given word count and initial data
148 buffer size. the caller will then fill in the command words and
149 data before calling cli_request_send() to send the reply on its
150 way. This interface is used before a session is setup.
152 struct cli_request *cli_request_setup_session(struct cli_session *session,
153 uint8_t command, uint_t wct, uint_t buflen)
155 struct cli_request *req;
157 uint32_t capabilities;
159 req = cli_request_setup_transport(session->transport, command, wct, buflen);
161 if (!req) return NULL;
163 req->session = session;
165 flags2 = FLAGS2_LONG_PATH_COMPONENTS;
166 capabilities = session->transport->negotiate.capabilities;
168 if (capabilities & CAP_UNICODE) {
169 flags2 |= FLAGS2_UNICODE_STRINGS;
171 if (capabilities & CAP_STATUS32) {
172 flags2 |= FLAGS2_32_BIT_ERROR_CODES;
174 if (capabilities & CAP_EXTENDED_SECURITY) {
175 flags2 |= FLAGS2_EXTENDED_SECURITY;
177 if (session->transport->negotiate.sign_info.doing_signing) {
178 flags2 |= FLAGS2_SMB_SECURITY_SIGNATURES;
181 SSVAL(req->out.hdr, HDR_FLG2, flags2);
182 SSVAL(req->out.hdr, HDR_PID, session->pid & 0xFFFF);
183 SSVAL(req->out.hdr, HDR_PIDHIGH, session->pid >> 16);
184 SSVAL(req->out.hdr, HDR_UID, session->vuid);
190 setup a request for tree based commands
192 struct cli_request *cli_request_setup(struct cli_tree *tree,
194 uint_t wct, uint_t buflen)
196 struct cli_request *req;
198 req = cli_request_setup_session(tree->session, command, wct, buflen);
201 SSVAL(req->out.hdr,HDR_TID,tree->tid);
207 grow the allocation of the data buffer portion of a reply
208 packet. Note that as this can reallocate the packet buffer this
209 invalidates any local pointers into the packet.
211 To cope with this req->out.ptr is supplied. This will be updated to
212 point at the same offset into the packet as before this call
214 static void cli_req_grow_allocation(struct cli_request *req, uint_t new_size)
219 delta = new_size - req->out.data_size;
220 if (delta + req->out.size <= req->out.allocated) {
221 /* it fits in the preallocation */
225 /* we need to realloc */
226 req->out.allocated = req->out.size + delta + REQ_OVER_ALLOCATION;
227 buf2 = talloc_realloc(req->mem_ctx, req->out.buffer, req->out.allocated);
229 smb_panic("out of memory in req_grow_allocation");
232 if (buf2 == req->out.buffer) {
233 /* the malloc library gave us the same pointer */
237 /* update the pointers into the packet */
238 req->out.data = buf2 + PTR_DIFF(req->out.data, req->out.buffer);
239 req->out.ptr = buf2 + PTR_DIFF(req->out.ptr, req->out.buffer);
240 req->out.vwv = buf2 + PTR_DIFF(req->out.vwv, req->out.buffer);
241 req->out.hdr = buf2 + PTR_DIFF(req->out.hdr, req->out.buffer);
243 req->out.buffer = buf2;
248 grow the data buffer portion of a reply packet. Note that as this
249 can reallocate the packet buffer this invalidates any local pointers
252 To cope with this req->out.ptr is supplied. This will be updated to
253 point at the same offset into the packet as before this call
255 static void cli_req_grow_data(struct cli_request *req, uint_t new_size)
259 cli_req_grow_allocation(req, new_size);
261 delta = new_size - req->out.data_size;
263 req->out.size += delta;
264 req->out.data_size += delta;
266 /* set the BCC to the new data size */
267 SSVAL(req->out.vwv, VWV(req->out.wct), new_size);
274 BOOL cli_request_send(struct cli_request *req)
276 if (IVAL(req->out.buffer, 0) == 0) {
277 _smb_setlen(req->out.buffer, req->out.size - NBT_HDR_SIZE);
280 cli_request_calculate_sign_mac(req);
282 cli_transport_send(req);
289 receive a response to a packet
291 BOOL cli_request_receive(struct cli_request *req)
293 /* req can be NULL when a send has failed. This eliminates lots of NULL
294 checks in each module */
295 if (!req) return False;
297 /* keep receiving packets until this one is replied to */
298 while (req->state <= CLI_REQUEST_RECV) {
299 event_loop_once(req->transport->event.ctx);
307 handle oplock break requests from the server - return True if the request was
310 BOOL handle_oplock_break(struct cli_transport *transport, uint_t len, const char *hdr, const char *vwv)
312 /* we must be very fussy about what we consider an oplock break to avoid
313 matching readbraw replies */
314 if (len != MIN_SMB_SIZE + VWV(8) ||
315 (CVAL(hdr, HDR_FLG) & FLAG_REPLY) ||
316 CVAL(hdr,HDR_COM) != SMBlockingX ||
317 SVAL(hdr, HDR_MID) != 0xFFFF ||
318 SVAL(vwv,VWV(6)) != 0 ||
319 SVAL(vwv,VWV(7)) != 0) {
323 if (transport->oplock.handler) {
324 uint16_t tid = SVAL(hdr, HDR_TID);
325 uint16_t fnum = SVAL(vwv,VWV(2));
326 uint8_t level = CVAL(vwv,VWV(3)+1);
327 transport->oplock.handler(transport, tid, fnum, level, transport->oplock.private);
334 wait for a reply to be received for a packet that just returns an error
335 code and nothing more
337 NTSTATUS cli_request_simple_recv(struct cli_request *req)
339 cli_request_receive(req);
340 return cli_request_destroy(req);
344 /* Return true if the last packet was in error */
345 BOOL cli_request_is_error(struct cli_request *req)
347 return NT_STATUS_IS_ERR(req->status);
351 append a string into the data portion of the request packet
353 return the number of bytes added to the packet
355 size_t cli_req_append_string(struct cli_request *req, const char *str, uint_t flags)
359 /* determine string type to use */
360 if (!(flags & (STR_ASCII|STR_UNICODE))) {
361 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
364 len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
366 cli_req_grow_allocation(req, len + req->out.data_size);
368 len = push_string(NULL, req->out.data + req->out.data_size, str, len, flags);
370 cli_req_grow_data(req, len + req->out.data_size);
376 this is like cli_req_append_string but it also return the
377 non-terminated string byte length, which can be less than the number
378 of bytes consumed in the packet for 2 reasons:
380 1) the string in the packet may be null terminated
381 2) the string in the packet may need a 1 byte UCS2 alignment
383 this is used in places where the non-terminated string byte length is
384 placed in the packet as a separate field
386 size_t cli_req_append_string_len(struct cli_request *req, const char *str, uint_t flags, int *len)
391 /* determine string type to use */
392 if (!(flags & (STR_ASCII|STR_UNICODE))) {
393 flags |= (req->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
396 /* see if an alignment byte will be used */
397 if ((flags & STR_UNICODE) && !(flags & STR_NOALIGN)) {
398 diff = ucs2_align(NULL, req->out.data + req->out.data_size, flags);
401 /* do the hard work */
402 ret = cli_req_append_string(req, str, flags);
404 /* see if we need to subtract the termination */
405 if (flags & STR_TERMINATE) {
406 diff += (flags & STR_UNICODE) ? 2 : 1;
420 push a string into the data portion of the request packet, growing it if necessary
421 this gets quite tricky - please be very careful to cover all cases when modifying this
423 if dest is NULL, then put the string at the end of the data portion of the packet
425 if dest_len is -1 then no limit applies
427 size_t cli_req_append_ascii4(struct cli_request *req, const char *str, uint_t flags)
430 cli_req_append_bytes(req, (const uint8_t *)"\4", 1);
431 size = cli_req_append_string(req, str, flags);
437 push a blob into the data portion of the request packet, growing it if necessary
438 this gets quite tricky - please be very careful to cover all cases when modifying this
440 if dest is NULL, then put the blob at the end of the data portion of the packet
442 size_t cli_req_append_blob(struct cli_request *req, const DATA_BLOB *blob)
444 cli_req_grow_allocation(req, req->out.data_size + blob->length);
445 memcpy(req->out.data + req->out.data_size, blob->data, blob->length);
446 cli_req_grow_data(req, req->out.data_size + blob->length);
451 append raw bytes into the data portion of the request packet
452 return the number of bytes added
454 size_t cli_req_append_bytes(struct cli_request *req, const uint8_t *bytes, size_t byte_len)
456 cli_req_grow_allocation(req, byte_len + req->out.data_size);
457 memcpy(req->out.data + req->out.data_size, bytes, byte_len);
458 cli_req_grow_data(req, byte_len + req->out.data_size);
463 append variable block (type 5 buffer) into the data portion of the request packet
464 return the number of bytes added
466 size_t cli_req_append_var_block(struct cli_request *req, const uint8_t *bytes, uint16_t byte_len)
468 cli_req_grow_allocation(req, byte_len + 3 + req->out.data_size);
469 SCVAL(req->out.data + req->out.data_size, 0, 5);
470 SSVAL(req->out.data + req->out.data_size, 1, byte_len); /* add field length */
472 memcpy(req->out.data + req->out.data_size + 3, bytes, byte_len);
474 cli_req_grow_data(req, byte_len + 3 + req->out.data_size);
480 pull a UCS2 string from a request packet, returning a talloced unix string
482 the string length is limited by the 3 things:
483 - the data size in the request (end of packet)
484 - the passed 'byte_len' if it is not -1
485 - the end of string (null termination)
487 Note that 'byte_len' is the number of bytes in the packet
489 on failure zero is returned and *dest is set to NULL, otherwise the number
490 of bytes consumed in the packet is returned
492 static size_t cli_req_pull_ucs2(struct cli_request *req, TALLOC_CTX *mem_ctx,
493 char **dest, const char *src, int byte_len, uint_t flags)
495 int src_len, src_len2, alignment=0;
498 if (!(flags & STR_NOALIGN) && ucs2_align(req->in.buffer, src, flags)) {
501 if (byte_len != -1) {
506 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
511 if (byte_len != -1 && src_len > byte_len) {
515 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
516 if (src_len2 < src_len - 2) {
517 /* include the termination if we didn't reach the end of the packet */
521 /* ucs2 strings must be at least 2 bytes long */
527 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
533 return src_len2 + alignment;
537 pull a ascii string from a request packet, returning a talloced string
539 the string length is limited by the 3 things:
540 - the data size in the request (end of packet)
541 - the passed 'byte_len' if it is not -1
542 - the end of string (null termination)
544 Note that 'byte_len' is the number of bytes in the packet
546 on failure zero is returned and *dest is set to NULL, otherwise the number
547 of bytes consumed in the packet is returned
549 size_t cli_req_pull_ascii(struct cli_request *req, TALLOC_CTX *mem_ctx,
550 char **dest, const char *src, int byte_len, uint_t flags)
552 int src_len, src_len2;
555 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
560 if (byte_len != -1 && src_len > byte_len) {
563 src_len2 = strnlen(src, src_len);
564 if (src_len2 < src_len - 1) {
565 /* include the termination if we didn't reach the end of the packet */
569 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
580 pull a string from a request packet, returning a talloced string
582 the string length is limited by the 3 things:
583 - the data size in the request (end of packet)
584 - the passed 'byte_len' if it is not -1
585 - the end of string (null termination)
587 Note that 'byte_len' is the number of bytes in the packet
589 on failure zero is returned and *dest is set to NULL, otherwise the number
590 of bytes consumed in the packet is returned
592 size_t cli_req_pull_string(struct cli_request *req, TALLOC_CTX *mem_ctx,
593 char **dest, const char *src, int byte_len, uint_t flags)
595 if (!(flags & STR_ASCII) &&
596 (((flags & STR_UNICODE) || (req->flags2 & FLAGS2_UNICODE_STRINGS)))) {
597 return cli_req_pull_ucs2(req, mem_ctx, dest, src, byte_len, flags);
600 return cli_req_pull_ascii(req, mem_ctx, dest, src, byte_len, flags);
605 pull a DATA_BLOB from a reply packet, returning a talloced blob
606 make sure we don't go past end of packet
608 if byte_len is -1 then limit the blob only by packet size
610 DATA_BLOB cli_req_pull_blob(struct cli_request *req, TALLOC_CTX *mem_ctx, const char *src, int byte_len)
614 src_len = req->in.data_size - PTR_DIFF(src, req->in.data);
617 return data_blob(NULL, 0);
620 if (byte_len != -1 && src_len > byte_len) {
624 return data_blob_talloc(mem_ctx, src, src_len);
627 /* check that a lump of data in a request is within the bounds of the data section of
629 static BOOL cli_req_data_oob(struct cli_request *req, const char *ptr, uint32_t count)
631 /* be careful with wraparound! */
632 if (ptr < req->in.data ||
633 ptr >= req->in.data + req->in.data_size ||
634 count > req->in.data_size ||
635 ptr + count > req->in.data + req->in.data_size) {
642 pull a lump of data from a request packet
644 return False if any part is outside the data portion of the packet
646 BOOL cli_raw_pull_data(struct cli_request *req, const char *src, int len, char *dest)
648 if (len == 0) return True;
650 if (cli_req_data_oob(req, src, len)) {
654 memcpy(dest, src, len);
660 put a NTTIME into a packet
662 void cli_push_nttime(void *base, uint16_t offset, NTTIME t)
664 SBVAL(base, offset, t);
668 pull a NTTIME from a packet
670 NTTIME cli_pull_nttime(void *base, uint16_t offset)
672 NTTIME ret = BVAL(base, offset);
677 pull a UCS2 string from a blob, returning a talloced unix string
679 the string length is limited by the 3 things:
680 - the data size in the blob
681 - the passed 'byte_len' if it is not -1
682 - the end of string (null termination)
684 Note that 'byte_len' is the number of bytes in the packet
686 on failure zero is returned and *dest is set to NULL, otherwise the number
687 of bytes consumed in the blob is returned
689 static size_t cli_blob_pull_ucs2(TALLOC_CTX* mem_ctx,
690 DATA_BLOB *blob, const char **dest,
691 const char *src, int byte_len, uint_t flags)
693 int src_len, src_len2, alignment=0;
696 if (src < (const char *)blob->data ||
697 src >= (const char *)(blob->data + blob->length)) {
702 src_len = blob->length - PTR_DIFF(src, blob->data);
704 if (byte_len != -1 && src_len > byte_len) {
708 if (!(flags & STR_NOALIGN) && ucs2_align(blob->data, src, flags)) {
719 src_len2 = strnlen_w((const smb_ucs2_t *)src, src_len/2) * 2;
721 if (src_len2 < src_len - 2) {
722 /* include the termination if we didn't reach the end of the packet */
726 ret = convert_string_talloc(mem_ctx, CH_UCS2, CH_UNIX, src, src_len2, (const void **)dest);
732 return src_len2 + alignment;
736 pull a ascii string from a blob, returning a talloced string
738 the string length is limited by the 3 things:
739 - the data size in the blob
740 - the passed 'byte_len' if it is not -1
741 - the end of string (null termination)
743 Note that 'byte_len' is the number of bytes in the blob
745 on failure zero is returned and *dest is set to NULL, otherwise the number
746 of bytes consumed in the blob is returned
748 static size_t cli_blob_pull_ascii(TALLOC_CTX *mem_ctx,
749 DATA_BLOB *blob, const char **dest,
750 const char *src, int byte_len, uint_t flags)
752 int src_len, src_len2;
755 src_len = blob->length - PTR_DIFF(src, blob->data);
760 if (byte_len != -1 && src_len > byte_len) {
763 src_len2 = strnlen(src, src_len);
765 if (src_len2 < src_len - 1) {
766 /* include the termination if we didn't reach the end of the packet */
770 ret = convert_string_talloc(mem_ctx, CH_DOS, CH_UNIX, src, src_len2, (const void **)dest);
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 cli_blob_pull_string(struct cli_session *session,
798 uint16_t len_offset, uint16_t str_offset,
804 if (len_offset > blob->length-4) {
807 if (flags & STR_LEN8BIT) {
808 dest->private_length = CVAL(blob->data, len_offset);
810 dest->private_length = IVAL(blob->data, len_offset);
814 if (!(flags & STR_ASCII) &&
815 ((flags & STR_UNICODE) ||
816 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
818 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
821 if (flags & STR_LEN_NOTERM) {
824 return align + extra + cli_blob_pull_ucs2(mem_ctx, blob, &dest->s,
825 blob->data+str_offset+align,
826 dest->private_length, flags);
829 if (flags & STR_LEN_NOTERM) {
833 return extra + cli_blob_pull_ascii(mem_ctx, blob, &dest->s,
834 blob->data+str_offset, dest->private_length, flags);
838 pull a string from a blob, returning a talloced char *
840 Currently only used by the UNIX search info level.
842 the string length is limited by 2 things:
843 - the data size in the blob
844 - the end of string (null termination)
846 on failure zero is returned and dest->s is set to NULL, otherwise the number
847 of bytes consumed in the blob is returned
849 size_t cli_blob_pull_unix_string(struct cli_session *session,
859 if (!(flags & STR_ASCII) &&
860 ((flags & STR_UNICODE) ||
861 (session->transport->negotiate.capabilities & CAP_UNICODE))) {
863 if ((str_offset&1) && !(flags & STR_NOALIGN)) {
866 if (flags & STR_LEN_NOTERM) {
869 return align + extra + cli_blob_pull_ucs2(mem_ctx, blob, dest,
870 blob->data+str_offset+align,
874 if (flags & STR_LEN_NOTERM) {
878 return extra + cli_blob_pull_ascii(mem_ctx, blob, dest,
879 blob->data+str_offset, -1, flags);
884 append a string into a blob
886 size_t cli_blob_append_string(struct cli_session *session,
887 TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
888 const char *str, uint_t flags)
895 /* determine string type to use */
896 if (!(flags & (STR_ASCII|STR_UNICODE))) {
897 flags |= (session->transport->negotiate.capabilities & CAP_UNICODE) ? STR_UNICODE : STR_ASCII;
900 max_len = (strlen(str)+2) * MAX_BYTES_PER_CHAR;
902 blob->data = talloc_realloc(mem_ctx, blob->data, blob->length + max_len);
907 len = push_string(NULL, blob->data + blob->length, str, max_len, flags);