• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/libcli/smb2/
1/*
2   Unix SMB/CIFS implementation.
3
4   SMB2 client tree handling
5
6   Copyright (C) Andrew Tridgell 2005
7
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 3 of the License, or
11   (at your option) any later version.
12
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.
17
18   You should have received a copy of the GNU General Public License
19   along with this program.  If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include "includes.h"
23#include "libcli/raw/libcliraw.h"
24#include "libcli/raw/raw_proto.h"
25#include "libcli/smb2/smb2.h"
26#include "libcli/smb2/smb2_calls.h"
27#include "librpc/gen_ndr/ndr_security.h"
28
29/*
30  send a create request
31*/
32struct smb2_request *smb2_create_send(struct smb2_tree *tree, struct smb2_create *io)
33{
34	struct smb2_request *req;
35	NTSTATUS status;
36	DATA_BLOB blob;
37	struct smb2_create_blobs blobs;
38	int i;
39
40	ZERO_STRUCT(blobs);
41
42	req = smb2_request_init_tree(tree, SMB2_OP_CREATE, 0x38, true, 0);
43	if (req == NULL) return NULL;
44
45	SCVAL(req->out.body, 0x02, io->in.security_flags);
46	SCVAL(req->out.body, 0x03, io->in.oplock_level);
47	SIVAL(req->out.body, 0x04, io->in.impersonation_level);
48	SBVAL(req->out.body, 0x08, io->in.create_flags);
49	SBVAL(req->out.body, 0x10, io->in.reserved);
50	SIVAL(req->out.body, 0x18, io->in.desired_access);
51	SIVAL(req->out.body, 0x1C, io->in.file_attributes);
52	SIVAL(req->out.body, 0x20, io->in.share_access);
53	SIVAL(req->out.body, 0x24, io->in.create_disposition);
54	SIVAL(req->out.body, 0x28, io->in.create_options);
55
56	status = smb2_push_o16s16_string(&req->out, 0x2C, io->in.fname);
57	if (!NT_STATUS_IS_OK(status)) {
58		talloc_free(req);
59		return NULL;
60	}
61
62	/* now add all the optional blobs */
63	if (io->in.eas.num_eas != 0) {
64		DATA_BLOB b = data_blob_talloc(req, NULL,
65					       ea_list_size_chained(io->in.eas.num_eas, io->in.eas.eas, 4));
66		ea_put_list_chained(b.data, io->in.eas.num_eas, io->in.eas.eas, 4);
67		status = smb2_create_blob_add(req, &blobs,
68					      SMB2_CREATE_TAG_EXTA, b);
69		if (!NT_STATUS_IS_OK(status)) {
70			talloc_free(req);
71			return NULL;
72		}
73		data_blob_free(&b);
74	}
75
76	/* an empty MxAc tag seems to be used to ask the server to
77	   return the maximum access mask allowed on the file */
78	if (io->in.query_maximal_access) {
79		/* TODO: MS-SMB2 2.2.13.2.5 says this can contain a timestamp? What to do
80		   with that if it doesn't match? */
81		status = smb2_create_blob_add(req, &blobs,
82					      SMB2_CREATE_TAG_MXAC, data_blob(NULL, 0));
83		if (!NT_STATUS_IS_OK(status)) {
84			talloc_free(req);
85			return NULL;
86		}
87	}
88
89	if (io->in.alloc_size != 0) {
90		uint8_t data[8];
91		SBVAL(data, 0, io->in.alloc_size);
92		status = smb2_create_blob_add(req, &blobs,
93					      SMB2_CREATE_TAG_ALSI, data_blob_const(data, 8));
94		if (!NT_STATUS_IS_OK(status)) {
95			talloc_free(req);
96			return NULL;
97		}
98	}
99
100	if (io->in.durable_open) {
101		status = smb2_create_blob_add(req, &blobs,
102					      SMB2_CREATE_TAG_DHNQ, data_blob_talloc_zero(req, 16));
103		if (!NT_STATUS_IS_OK(status)) {
104			talloc_free(req);
105			return NULL;
106		}
107	}
108
109	if (io->in.durable_handle) {
110		uint8_t data[16];
111		smb2_push_handle(data, io->in.durable_handle);
112		status = smb2_create_blob_add(req, &blobs,
113					      SMB2_CREATE_TAG_DHNC, data_blob_const(data, 16));
114		if (!NT_STATUS_IS_OK(status)) {
115			talloc_free(req);
116			return NULL;
117		}
118	}
119
120	if (io->in.timewarp) {
121		uint8_t data[8];
122		SBVAL(data, 0, io->in.timewarp);
123		status = smb2_create_blob_add(req, &blobs,
124					      SMB2_CREATE_TAG_TWRP, data_blob_const(data, 8));
125		if (!NT_STATUS_IS_OK(status)) {
126			talloc_free(req);
127			return NULL;
128		}
129	}
130
131	if (io->in.sec_desc) {
132		enum ndr_err_code ndr_err;
133		DATA_BLOB sd_blob;
134		ndr_err = ndr_push_struct_blob(&sd_blob, req, NULL,
135					       io->in.sec_desc,
136					       (ndr_push_flags_fn_t)ndr_push_security_descriptor);
137		if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
138			talloc_free(req);
139			return NULL;
140		}
141		status = smb2_create_blob_add(req, &blobs,
142					      SMB2_CREATE_TAG_SECD, sd_blob);
143		if (!NT_STATUS_IS_OK(status)) {
144			talloc_free(req);
145			return NULL;
146		}
147	}
148
149	if (io->in.query_on_disk_id) {
150		status = smb2_create_blob_add(req, &blobs,
151					      SMB2_CREATE_TAG_QFID, data_blob(NULL, 0));
152		if (!NT_STATUS_IS_OK(status)) {
153			talloc_free(req);
154			return NULL;
155		}
156	}
157
158	if (io->in.lease_request) {
159		uint8_t data[32];
160
161		memcpy(&data[0], &io->in.lease_request->lease_key, 16);
162		SIVAL(data, 16, io->in.lease_request->lease_state);
163		SIVAL(data, 20, io->in.lease_request->lease_flags);
164		SBVAL(data, 24, io->in.lease_request->lease_duration);
165
166		status = smb2_create_blob_add(req, &blobs,
167					      SMB2_CREATE_TAG_RQLS,
168					      data_blob_const(data, 32));
169		if (!NT_STATUS_IS_OK(status)) {
170			talloc_free(req);
171			return NULL;
172		}
173	}
174
175	/* and any custom blobs */
176	for (i=0;i<io->in.blobs.num_blobs;i++) {
177		status = smb2_create_blob_add(req, &blobs,
178					      io->in.blobs.blobs[i].tag,
179					      io->in.blobs.blobs[i].data);
180		if (!NT_STATUS_IS_OK(status)) {
181			talloc_free(req);
182			return NULL;
183		}
184	}
185
186
187	status = smb2_create_blob_push(req, &blob, blobs);
188	if (!NT_STATUS_IS_OK(status)) {
189		talloc_free(req);
190		return NULL;
191	}
192
193	status = smb2_push_o32s32_blob(&req->out, 0x30, blob);
194	if (!NT_STATUS_IS_OK(status)) {
195		talloc_free(req);
196		return NULL;
197	}
198
199	data_blob_free(&blob);
200
201	smb2_transport_send(req);
202
203	return req;
204}
205
206
207/*
208  recv a create reply
209*/
210NTSTATUS smb2_create_recv(struct smb2_request *req, TALLOC_CTX *mem_ctx, struct smb2_create *io)
211{
212	NTSTATUS status;
213	DATA_BLOB blob;
214	int i;
215
216	if (!smb2_request_receive(req) ||
217	    !smb2_request_is_ok(req)) {
218		return smb2_request_destroy(req);
219	}
220
221	SMB2_CHECK_PACKET_RECV(req, 0x58, true);
222	ZERO_STRUCT(io->out);
223	io->out.oplock_level   = CVAL(req->in.body, 0x02);
224	io->out.reserved       = CVAL(req->in.body, 0x03);
225	io->out.create_action  = IVAL(req->in.body, 0x04);
226	io->out.create_time    = smbcli_pull_nttime(req->in.body, 0x08);
227	io->out.access_time    = smbcli_pull_nttime(req->in.body, 0x10);
228	io->out.write_time     = smbcli_pull_nttime(req->in.body, 0x18);
229	io->out.change_time    = smbcli_pull_nttime(req->in.body, 0x20);
230	io->out.alloc_size     = BVAL(req->in.body, 0x28);
231	io->out.size           = BVAL(req->in.body, 0x30);
232	io->out.file_attr      = IVAL(req->in.body, 0x38);
233	io->out.reserved2      = IVAL(req->in.body, 0x3C);
234	smb2_pull_handle(req->in.body+0x40, &io->out.file.handle);
235	status = smb2_pull_o32s32_blob(&req->in, mem_ctx, req->in.body+0x50, &blob);
236	if (!NT_STATUS_IS_OK(status)) {
237		smb2_request_destroy(req);
238		return status;
239	}
240
241	status = smb2_create_blob_parse(mem_ctx, blob, &io->out.blobs);
242	if (!NT_STATUS_IS_OK(status)) {
243		smb2_request_destroy(req);
244		return status;
245	}
246
247	/* pull out the parsed blobs */
248	for (i=0;i<io->out.blobs.num_blobs;i++) {
249		if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_MXAC) == 0) {
250			/* TODO: this also contains a status field in
251			   first 4 bytes */
252			if (io->out.blobs.blobs[i].data.length != 8) {
253				smb2_request_destroy(req);
254				return NT_STATUS_INVALID_NETWORK_RESPONSE;
255			}
256			io->out.maximal_access = IVAL(io->out.blobs.blobs[i].data.data, 4);
257		}
258		if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_QFID) == 0) {
259			if (io->out.blobs.blobs[i].data.length != 32) {
260				smb2_request_destroy(req);
261				return NT_STATUS_INVALID_NETWORK_RESPONSE;
262			}
263			memcpy(io->out.on_disk_id, io->out.blobs.blobs[i].data.data, 32);
264		}
265		if (strcmp(io->out.blobs.blobs[i].tag, SMB2_CREATE_TAG_RQLS) == 0) {
266			uint8_t *data;
267			if (io->out.blobs.blobs[i].data.length != 32) {
268				smb2_request_destroy(req);
269				return NT_STATUS_INVALID_NETWORK_RESPONSE;
270			}
271
272			data = io->out.blobs.blobs[i].data.data;
273			memcpy(&io->out.lease_response.lease_key, data, 16);
274			io->out.lease_response.lease_state = IVAL(data, 16);
275			io->out.lease_response.lease_flags = IVAL(data, 20);
276			io->out.lease_response.lease_duration = BVAL(data, 24);
277		}
278	}
279
280	data_blob_free(&blob);
281
282	return smb2_request_destroy(req);
283}
284
285/*
286  sync create request
287*/
288NTSTATUS smb2_create(struct smb2_tree *tree, TALLOC_CTX *mem_ctx, struct smb2_create *io)
289{
290	struct smb2_request *req = smb2_create_send(tree, io);
291	return smb2_create_recv(req, mem_ctx, io);
292}
293