2 Unix SMB/CIFS implementation.
4 SMB2 client request handling
6 Copyright (C) Andrew Tridgell 2005
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "libcli/raw/libcliraw.h"
25 #include "libcli/smb2/smb2.h"
26 #include "libcli/smb2/smb2_calls.h"
27 #include "include/dlinklist.h"
28 #include "lib/events/events.h"
31 initialise a smb2 request
33 struct smb2_request *smb2_request_init(struct smb2_transport *transport,
34 uint16_t opcode, uint32_t body_size)
36 struct smb2_request *req;
38 req = talloc(transport, struct smb2_request);
39 if (req == NULL) return NULL;
41 req->state = SMB2_REQUEST_INIT;
42 req->transport = transport;
45 req->seqnum = transport->seqnum++;
46 req->status = NT_STATUS_OK;
48 req->next = req->prev = NULL;
52 req->out.allocated = SMB2_HDR_BODY+NBT_HDR_SIZE+body_size;
53 req->out.buffer = talloc_size(req, req->out.allocated);
54 if (req->out.buffer == NULL) {
59 req->out.size = SMB2_HDR_BODY+NBT_HDR_SIZE + body_size;
60 req->out.hdr = req->out.buffer + NBT_HDR_SIZE;
61 req->out.body = req->out.hdr + SMB2_HDR_BODY;
62 req->out.body_size = body_size;
63 req->out.ptr = req->out.body;
65 SIVAL(req->out.hdr, 0, SMB2_MAGIC);
66 SSVAL(req->out.hdr, SMB2_HDR_LENGTH, SMB2_HDR_BODY);
67 SSVAL(req->out.hdr, SMB2_HDR_PAD1, 0);
68 SIVAL(req->out.hdr, SMB2_HDR_STATUS, 0);
69 SSVAL(req->out.hdr, SMB2_HDR_OPCODE, opcode);
70 SSVAL(req->out.hdr, SMB2_HDR_PAD2, 0);
71 SIVAL(req->out.hdr, SMB2_HDR_FLAGS, 0);
72 SIVAL(req->out.hdr, SMB2_HDR_UNKNOWN, 0);
73 SBVAL(req->out.hdr, SMB2_HDR_SEQNUM, req->seqnum);
74 SIVAL(req->out.hdr, SMB2_HDR_PID, 0);
75 SIVAL(req->out.hdr, SMB2_HDR_TID, 0);
76 SBVAL(req->out.hdr, SMB2_HDR_UID, 0);
77 memset(req->out.hdr+SMB2_HDR_SIG, 0, 16);
83 initialise a smb2 request for tree operations
85 struct smb2_request *smb2_request_init_tree(struct smb2_tree *tree,
86 uint16_t opcode, uint32_t body_size)
88 struct smb2_request *req = smb2_request_init(tree->session->transport, opcode,
90 if (req == NULL) return NULL;
92 SBVAL(req->out.hdr, SMB2_HDR_UID, tree->session->uid);
93 SIVAL(req->out.hdr, SMB2_HDR_TID, tree->tid);
94 req->session = tree->session;
100 /* destroy a request structure and return final status */
101 NTSTATUS smb2_request_destroy(struct smb2_request *req)
105 /* this is the error code we give the application for when a
106 _send() call fails completely */
107 if (!req) return NT_STATUS_UNSUCCESSFUL;
109 if (req->transport) {
110 /* remove it from the list of pending requests (a null op if
111 its not in the list) */
112 DLIST_REMOVE(req->transport->pending_recv, req);
115 if (req->state == SMBCLI_REQUEST_ERROR &&
116 NT_STATUS_IS_OK(req->status)) {
117 req->status = NT_STATUS_INTERNAL_ERROR;
120 status = req->status;
126 receive a response to a packet
128 BOOL smb2_request_receive(struct smb2_request *req)
130 /* req can be NULL when a send has failed. This eliminates lots of NULL
131 checks in each module */
132 if (!req) return False;
134 /* keep receiving packets until this one is replied to */
135 while (req->state <= SMB2_REQUEST_RECV) {
136 if (event_loop_once(req->transport->socket->event.ctx) != 0) {
141 return req->state == SMB2_REQUEST_DONE;
144 /* Return true if the last packet was in error */
145 BOOL smb2_request_is_error(struct smb2_request *req)
147 return NT_STATUS_IS_ERR(req->status);
151 check if a range in the reply body is out of bounds
153 BOOL smb2_oob_in(struct smb2_request *req, const uint8_t *ptr, uint_t size)
155 /* be careful with wraparound! */
156 if (ptr < req->in.body ||
157 ptr >= req->in.body + req->in.body_size ||
158 size > req->in.body_size ||
159 ptr + size > req->in.body + req->in.body_size) {
166 check if a range in the outgoing body is out of bounds
168 BOOL smb2_oob_out(struct smb2_request *req, const uint8_t *ptr, uint_t size)
170 /* be careful with wraparound! */
171 if (ptr < req->out.body ||
172 ptr >= req->out.body + req->out.body_size ||
173 size > req->out.body_size ||
174 ptr + size > req->out.body + req->out.body_size) {
181 pull a data blob from the body of a reply
183 DATA_BLOB smb2_pull_blob(struct smb2_request *req, uint8_t *ptr, uint_t size)
185 if (smb2_oob_in(req, ptr, size)) {
186 return data_blob(NULL, 0);
188 return data_blob_talloc(req, ptr, size);
192 pull a ofs/length/blob triple from a data blob
193 the ptr points to the start of the offset/length pair
195 NTSTATUS smb2_pull_ofs_blob(struct smb2_request *req, uint8_t *ptr, DATA_BLOB *blob)
198 if (smb2_oob_in(req, ptr, 4)) {
199 return NT_STATUS_BUFFER_TOO_SMALL;
203 if (smb2_oob_in(req, req->in.hdr + ofs, size)) {
204 return NT_STATUS_BUFFER_TOO_SMALL;
206 *blob = data_blob_talloc(req, req->in.hdr+ofs, size);
207 NT_STATUS_HAVE_NO_MEMORY(blob->data);
212 push a ofs/length/blob triple into a data blob
213 the ptr points to the start of the offset/length pair
215 NOTE: assumes blob goes immediately after the offset/length pair. Needs
218 NTSTATUS smb2_push_ofs_blob(struct smb2_request *req, uint8_t *ptr, DATA_BLOB blob)
220 if (smb2_oob_out(req, ptr, 4+blob.length)) {
221 return NT_STATUS_BUFFER_TOO_SMALL;
223 SSVAL(ptr, 0, 4 + (ptr - req->out.hdr));
224 SSVAL(ptr, 2, blob.length);
225 memcpy(ptr+4, blob.data, blob.length);
230 pull a string in a ofs/length/blob format
232 NTSTATUS smb2_pull_ofs_string(struct smb2_request *req, uint8_t *ptr,
239 status = smb2_pull_ofs_blob(req, ptr, &blob);
240 NT_STATUS_NOT_OK_RETURN(status);
241 size = convert_string_talloc(req, CH_UTF16, CH_UNIX,
242 blob.data, blob.length, &vstr);
243 data_blob_free(&blob);
246 return NT_STATUS_ILLEGAL_CHARACTER;
252 create a UTF16 string in a blob from a char*
254 NTSTATUS smb2_string_blob(TALLOC_CTX *mem_ctx, const char *str, DATA_BLOB *blob)
257 size = convert_string_talloc(mem_ctx, CH_UNIX, CH_UTF16,
258 str, strlen(str), (void **)&blob->data);
260 return NT_STATUS_ILLEGAL_CHARACTER;
268 put a file handle into a buffer
270 void smb2_put_handle(uint8_t *data, struct smb2_handle *h)
272 SBVAL(data, 0, h->data[0]);
273 SBVAL(data, 8, h->data[1]);