Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : RAW_QFS_* operations
5 :
6 : Copyright (C) Andrew Tridgell 2003
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 "librpc/gen_ndr/ndr_misc.h"
26 :
27 : /****************************************************************************
28 : Query FS Info - SMBdskattr call (async send)
29 : ****************************************************************************/
30 1 : static struct smbcli_request *smb_raw_dskattr_send(struct smbcli_tree *tree,
31 : union smb_fsinfo *fsinfo)
32 : {
33 0 : struct smbcli_request *req;
34 :
35 1 : req = smbcli_request_setup(tree, SMBdskattr, 0, 0);
36 1 : if (req == NULL) {
37 0 : return NULL;
38 : }
39 :
40 1 : if (!smbcli_request_send(req)) {
41 0 : smbcli_request_destroy(req);
42 0 : return NULL;
43 : }
44 :
45 1 : return req;
46 : }
47 :
48 : /****************************************************************************
49 : Query FS Info - SMBdskattr call (async recv)
50 : ****************************************************************************/
51 1 : static NTSTATUS smb_raw_dskattr_recv(struct smbcli_request *req,
52 : union smb_fsinfo *fsinfo)
53 : {
54 2 : if (!smbcli_request_receive(req) ||
55 1 : smbcli_request_is_error(req)) {
56 0 : goto failed;
57 : }
58 :
59 1 : SMBCLI_CHECK_WCT(req, 5);
60 1 : fsinfo->dskattr.out.units_total = SVAL(req->in.vwv, VWV(0));
61 1 : fsinfo->dskattr.out.blocks_per_unit = SVAL(req->in.vwv, VWV(1));
62 1 : fsinfo->dskattr.out.block_size = SVAL(req->in.vwv, VWV(2));
63 1 : fsinfo->dskattr.out.units_free = SVAL(req->in.vwv, VWV(3));
64 :
65 1 : failed:
66 1 : return smbcli_request_destroy(req);
67 : }
68 :
69 :
70 : /****************************************************************************
71 : RAW_QFS_ trans2 interface via blobs (async send)
72 : ****************************************************************************/
73 2110 : static struct smbcli_request *smb_raw_qfsinfo_send(struct smbcli_tree *tree,
74 : TALLOC_CTX *mem_ctx,
75 : uint16_t info_level)
76 : {
77 0 : struct smb_trans2 tp;
78 2110 : uint16_t setup = TRANSACT2_QFSINFO;
79 :
80 2110 : tp.in.max_setup = 0;
81 2110 : tp.in.flags = 0;
82 2110 : tp.in.timeout = 0;
83 2110 : tp.in.setup_count = 1;
84 2110 : tp.in.max_param = 0;
85 2110 : tp.in.max_data = 0xFFFF;
86 2110 : tp.in.setup = &setup;
87 2110 : tp.in.data = data_blob(NULL, 0);
88 2110 : tp.in.timeout = 0;
89 :
90 2110 : tp.in.params = data_blob_talloc(mem_ctx, NULL, 2);
91 2110 : if (!tp.in.params.data) {
92 0 : return NULL;
93 : }
94 2110 : SSVAL(tp.in.params.data, 0, info_level);
95 :
96 2110 : return smb_raw_trans2_send(tree, &tp);
97 : }
98 :
99 : /****************************************************************************
100 : RAW_QFS_ trans2 interface via blobs (async recv)
101 : ****************************************************************************/
102 2114 : static NTSTATUS smb_raw_qfsinfo_blob_recv(struct smbcli_request *req,
103 : TALLOC_CTX *mem_ctx,
104 : DATA_BLOB *blob)
105 : {
106 0 : struct smb_trans2 tp;
107 0 : NTSTATUS status;
108 :
109 2114 : status = smb_raw_trans2_recv(req, mem_ctx, &tp);
110 :
111 2114 : if (NT_STATUS_IS_OK(status)) {
112 127 : (*blob) = tp.out.data;
113 : }
114 :
115 2114 : return status;
116 : }
117 :
118 :
119 : /* local macros to make the code more readable */
120 : #define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \
121 : DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \
122 : (int)blob.length, fsinfo->generic.level, (size))); \
123 : status = NT_STATUS_INFO_LENGTH_MISMATCH; \
124 : goto failed; \
125 : }
126 : #define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \
127 : DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \
128 : (int)blob.length, fsinfo->generic.level, (size))); \
129 : status = NT_STATUS_INFO_LENGTH_MISMATCH; \
130 : goto failed; \
131 : }
132 :
133 :
134 : /****************************************************************************
135 : Query FSInfo raw interface (async send)
136 : ****************************************************************************/
137 2111 : struct smbcli_request *smb_raw_fsinfo_send(struct smbcli_tree *tree,
138 : TALLOC_CTX *mem_ctx,
139 : union smb_fsinfo *fsinfo)
140 : {
141 0 : uint16_t info_level;
142 :
143 : /* handle the only non-trans2 call separately */
144 2111 : if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
145 1 : return smb_raw_dskattr_send(tree, fsinfo);
146 : }
147 2110 : if (fsinfo->generic.level >= RAW_QFS_GENERIC) {
148 0 : return NULL;
149 : }
150 :
151 : /* the headers map the trans2 levels direct to info levels */
152 2110 : info_level = (uint16_t)fsinfo->generic.level;
153 :
154 2110 : return smb_raw_qfsinfo_send(tree, mem_ctx, info_level);
155 : }
156 :
157 : /*
158 : parse the fsinfo 'passthru' level replies
159 : */
160 541 : NTSTATUS smb_raw_fsinfo_passthru_parse(DATA_BLOB blob, TALLOC_CTX *mem_ctx,
161 : enum smb_fsinfo_level level,
162 : union smb_fsinfo *fsinfo)
163 : {
164 541 : NTSTATUS status = NT_STATUS_OK;
165 0 : int i;
166 :
167 : /* parse the results */
168 541 : switch (level) {
169 13 : case RAW_QFS_VOLUME_INFORMATION:
170 13 : QFS_CHECK_MIN_SIZE(18);
171 13 : fsinfo->volume_info.out.create_time = smbcli_pull_nttime(blob.data, 0);
172 13 : fsinfo->volume_info.out.serial_number = IVAL(blob.data, 8);
173 13 : smbcli_blob_pull_string(NULL, mem_ctx, &blob,
174 : &fsinfo->volume_info.out.volume_name,
175 : 12, 18, STR_UNICODE);
176 541 : break;
177 :
178 25 : case RAW_QFS_SIZE_INFORMATION:
179 25 : QFS_CHECK_SIZE(24);
180 25 : fsinfo->size_info.out.total_alloc_units = BVAL(blob.data, 0);
181 25 : fsinfo->size_info.out.avail_alloc_units = BVAL(blob.data, 8);
182 25 : fsinfo->size_info.out.sectors_per_unit = IVAL(blob.data, 16);
183 25 : fsinfo->size_info.out.bytes_per_sector = IVAL(blob.data, 20);
184 25 : break;
185 :
186 13 : case RAW_QFS_DEVICE_INFORMATION:
187 13 : QFS_CHECK_SIZE(8);
188 13 : fsinfo->device_info.out.device_type = IVAL(blob.data, 0);
189 13 : fsinfo->device_info.out.characteristics = IVAL(blob.data, 4);
190 13 : break;
191 :
192 415 : case RAW_QFS_ATTRIBUTE_INFORMATION:
193 415 : QFS_CHECK_MIN_SIZE(12);
194 415 : fsinfo->attribute_info.out.fs_attr = IVAL(blob.data, 0);
195 415 : fsinfo->attribute_info.out.max_file_component_length = IVAL(blob.data, 4);
196 415 : smbcli_blob_pull_string(NULL, mem_ctx, &blob,
197 : &fsinfo->attribute_info.out.fs_type,
198 : 8, 12, STR_UNICODE);
199 415 : break;
200 :
201 5 : case RAW_QFS_QUOTA_INFORMATION:
202 5 : QFS_CHECK_SIZE(48);
203 5 : fsinfo->quota_information.out.unknown[0] = BVAL(blob.data, 0);
204 5 : fsinfo->quota_information.out.unknown[1] = BVAL(blob.data, 8);
205 5 : fsinfo->quota_information.out.unknown[2] = BVAL(blob.data, 16);
206 5 : fsinfo->quota_information.out.quota_soft = BVAL(blob.data, 24);
207 5 : fsinfo->quota_information.out.quota_hard = BVAL(blob.data, 32);
208 5 : fsinfo->quota_information.out.quota_flags = BVAL(blob.data, 40);
209 5 : break;
210 :
211 5 : case RAW_QFS_FULL_SIZE_INFORMATION:
212 5 : QFS_CHECK_SIZE(32);
213 5 : fsinfo->full_size_information.out.total_alloc_units = BVAL(blob.data, 0);
214 5 : fsinfo->full_size_information.out.call_avail_alloc_units = BVAL(blob.data, 8);
215 5 : fsinfo->full_size_information.out.actual_avail_alloc_units = BVAL(blob.data, 16);
216 5 : fsinfo->full_size_information.out.sectors_per_unit = IVAL(blob.data, 24);
217 5 : fsinfo->full_size_information.out.bytes_per_sector = IVAL(blob.data, 28);
218 5 : break;
219 :
220 54 : case RAW_QFS_OBJECTID_INFORMATION: {
221 54 : DATA_BLOB b2 = data_blob_const(blob.data, MIN(16, blob.length));
222 54 : QFS_CHECK_SIZE(64);
223 54 : status = GUID_from_ndr_blob(&b2, &fsinfo->objectid_information.out.guid);
224 54 : NT_STATUS_NOT_OK_RETURN(status);
225 378 : for (i=0;i<6;i++) {
226 324 : fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8);
227 : }
228 65 : break;
229 :
230 11 : case RAW_QFS_SECTOR_SIZE_INFORMATION:
231 11 : QFS_CHECK_SIZE(28);
232 0 : fsinfo->sector_size_info.out.logical_bytes_per_sector
233 11 : = IVAL(blob.data, 0);
234 0 : fsinfo->sector_size_info.out.phys_bytes_per_sector_atomic
235 11 : = IVAL(blob.data, 4);
236 0 : fsinfo->sector_size_info.out.phys_bytes_per_sector_perf
237 11 : = IVAL(blob.data, 8);
238 0 : fsinfo->sector_size_info.out.fs_effective_phys_bytes_per_sector_atomic
239 11 : = IVAL(blob.data, 12);
240 11 : fsinfo->sector_size_info.out.flags = IVAL(blob.data, 16);
241 0 : fsinfo->sector_size_info.out.byte_off_sector_align
242 11 : = IVAL(blob.data, 20);
243 0 : fsinfo->sector_size_info.out.byte_off_partition_align
244 11 : = IVAL(blob.data, 24);
245 11 : break;
246 : }
247 :
248 0 : default:
249 0 : status = NT_STATUS_INVALID_INFO_CLASS;
250 : }
251 :
252 541 : failed:
253 541 : return status;
254 : }
255 :
256 :
257 : /****************************************************************************
258 : Query FSInfo raw interface (async recv)
259 : ****************************************************************************/
260 2111 : NTSTATUS smb_raw_fsinfo_recv(struct smbcli_request *req,
261 : TALLOC_CTX *mem_ctx,
262 : union smb_fsinfo *fsinfo)
263 : {
264 0 : DATA_BLOB blob;
265 0 : NTSTATUS status;
266 2111 : struct smbcli_session *session = req?req->session:NULL;
267 :
268 2111 : if (fsinfo->generic.level == RAW_QFS_DSKATTR) {
269 1 : return smb_raw_dskattr_recv(req, fsinfo);
270 : }
271 :
272 2110 : status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
273 2110 : if (!NT_STATUS_IS_OK(status)) {
274 1987 : return status;
275 : }
276 :
277 : /* parse the results */
278 123 : switch (fsinfo->generic.level) {
279 0 : case RAW_QFS_GENERIC:
280 : case RAW_QFS_DSKATTR:
281 : /* handled above */
282 0 : break;
283 :
284 4 : case RAW_QFS_ALLOCATION:
285 4 : QFS_CHECK_SIZE(18);
286 4 : fsinfo->allocation.out.fs_id = IVAL(blob.data, 0);
287 4 : fsinfo->allocation.out.sectors_per_unit = IVAL(blob.data, 4);
288 4 : fsinfo->allocation.out.total_alloc_units = IVAL(blob.data, 8);
289 4 : fsinfo->allocation.out.avail_alloc_units = IVAL(blob.data, 12);
290 4 : fsinfo->allocation.out.bytes_per_sector = SVAL(blob.data, 16);
291 4 : break;
292 :
293 4 : case RAW_QFS_VOLUME:
294 4 : QFS_CHECK_MIN_SIZE(5);
295 4 : fsinfo->volume.out.serial_number = IVAL(blob.data, 0);
296 4 : smbcli_blob_pull_string(session, mem_ctx, &blob,
297 : &fsinfo->volume.out.volume_name,
298 : 4, 5, STR_LEN8BIT | STR_NOALIGN);
299 4 : break;
300 :
301 8 : case RAW_QFS_VOLUME_INFO:
302 : case RAW_QFS_VOLUME_INFORMATION:
303 8 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
304 : RAW_QFS_VOLUME_INFORMATION, fsinfo);
305 :
306 18 : case RAW_QFS_SIZE_INFO:
307 : case RAW_QFS_SIZE_INFORMATION:
308 18 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
309 : RAW_QFS_SIZE_INFORMATION, fsinfo);
310 :
311 8 : case RAW_QFS_DEVICE_INFO:
312 : case RAW_QFS_DEVICE_INFORMATION:
313 8 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
314 : RAW_QFS_DEVICE_INFORMATION, fsinfo);
315 :
316 15 : case RAW_QFS_ATTRIBUTE_INFO:
317 : case RAW_QFS_ATTRIBUTE_INFORMATION:
318 15 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
319 : RAW_QFS_ATTRIBUTE_INFORMATION, fsinfo);
320 :
321 4 : case RAW_QFS_UNIX_INFO:
322 4 : QFS_CHECK_SIZE(12);
323 4 : fsinfo->unix_info.out.major_version = SVAL(blob.data, 0);
324 4 : fsinfo->unix_info.out.minor_version = SVAL(blob.data, 2);
325 4 : fsinfo->unix_info.out.capability = SVAL(blob.data, 4);
326 4 : break;
327 :
328 4 : case RAW_QFS_QUOTA_INFORMATION:
329 4 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
330 : RAW_QFS_QUOTA_INFORMATION, fsinfo);
331 :
332 4 : case RAW_QFS_FULL_SIZE_INFORMATION:
333 4 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
334 : RAW_QFS_FULL_SIZE_INFORMATION, fsinfo);
335 :
336 53 : case RAW_QFS_OBJECTID_INFORMATION:
337 53 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
338 : RAW_QFS_OBJECTID_INFORMATION, fsinfo);
339 :
340 1 : case RAW_QFS_SECTOR_SIZE_INFORMATION:
341 1 : return smb_raw_fsinfo_passthru_parse(blob, mem_ctx,
342 : RAW_QFS_SECTOR_SIZE_INFORMATION, fsinfo);
343 : }
344 :
345 12 : failed:
346 12 : return status;
347 : }
348 :
349 : /****************************************************************************
350 : Query FSInfo raw interface (sync interface)
351 : ****************************************************************************/
352 60 : _PUBLIC_ NTSTATUS smb_raw_fsinfo(struct smbcli_tree *tree,
353 : TALLOC_CTX *mem_ctx,
354 : union smb_fsinfo *fsinfo)
355 : {
356 60 : struct smbcli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo);
357 60 : return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo);
358 : }
359 :
360 : /****************************************************************************
361 : Set FSInfo raw interface (async recv)
362 : ****************************************************************************/
363 4 : static NTSTATUS smb_raw_setfsinfo_recv(struct smbcli_request *req,
364 : TALLOC_CTX *mem_ctx,
365 : union smb_setfsinfo *set_fsinfo)
366 : {
367 4 : DATA_BLOB blob = data_blob_null;
368 0 : NTSTATUS status;
369 :
370 4 : if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) {
371 0 : return NT_STATUS_INVALID_PARAMETER;
372 : }
373 :
374 4 : status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob);
375 4 : data_blob_free(&blob);
376 4 : return status;
377 : }
378 :
379 : /****************************************************************************
380 : Set FSInfo raw interface (async send)
381 : ****************************************************************************/
382 4 : static struct smbcli_request *smb_raw_setfsinfo_send(struct smbcli_tree *tree,
383 : TALLOC_CTX *mem_ctx,
384 : union smb_setfsinfo *set_fsinfo)
385 : {
386 0 : struct smb_trans2 tp;
387 0 : uint16_t info_level;
388 4 : uint16_t setup = TRANSACT2_SETFSINFO;
389 :
390 4 : if (set_fsinfo->generic.level != RAW_SETFS_UNIX_INFO) {
391 0 : return NULL;
392 : }
393 4 : tp.in.max_setup = 0;
394 4 : tp.in.flags = 0;
395 4 : tp.in.timeout = 0;
396 4 : tp.in.setup_count = 1;
397 4 : tp.in.max_param = 0;
398 4 : tp.in.max_data = 0xFFFF;
399 4 : tp.in.setup = &setup;
400 4 : tp.in.timeout = 0;
401 :
402 4 : tp.in.params = data_blob_talloc(mem_ctx, NULL, 4);
403 4 : if (!tp.in.params.data) {
404 0 : return NULL;
405 : }
406 4 : info_level = (uint16_t)set_fsinfo->generic.level;
407 4 : SSVAL(tp.in.params.data, 0, 0);
408 4 : SSVAL(tp.in.params.data, 2, info_level);
409 :
410 4 : tp.in.data = data_blob_talloc(mem_ctx, NULL, 12);
411 4 : if (!tp.in.data.data) {
412 0 : return NULL;
413 : }
414 :
415 4 : SSVAL(tp.in.data.data, 0, set_fsinfo->unix_info.in.major_version);
416 4 : SSVAL(tp.in.data.data, 2, set_fsinfo->unix_info.in.minor_version);
417 4 : SBVAL(tp.in.data.data, 4, set_fsinfo->unix_info.in.capability);
418 :
419 4 : return smb_raw_trans2_send(tree, &tp);
420 : }
421 :
422 : /****************************************************************************
423 : Set FSInfo raw interface (sync interface)
424 : ****************************************************************************/
425 4 : _PUBLIC_ NTSTATUS smb_raw_setfsinfo(struct smbcli_tree *tree,
426 : TALLOC_CTX *mem_ctx,
427 : union smb_setfsinfo *set_fsinfo)
428 : {
429 4 : struct smbcli_request *req = smb_raw_setfsinfo_send(tree, mem_ctx, set_fsinfo);
430 4 : return smb_raw_setfsinfo_recv(req, mem_ctx, set_fsinfo);
431 : }
|