2 Unix SMB/CIFS implementation.
6 Copyright (C) Andrew Tridgell 2003
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.
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, see <http://www.gnu.org/licenses/>.
23 #include "libcli/raw/libcliraw.h"
24 #include "libcli/raw/raw_proto.h"
25 #include "librpc/gen_ndr/ndr_misc.h"
27 /****************************************************************************
28 Query FS Info - SMBdskattr call (async send)
29 ****************************************************************************/
30 static struct smbcli_request
*smb_raw_dskattr_send(struct smbcli_tree
*tree
,
31 union smb_fsinfo
*fsinfo
)
33 struct smbcli_request
*req
;
35 req
= smbcli_request_setup(tree
, SMBdskattr
, 0, 0);
40 if (!smbcli_request_send(req
)) {
41 smbcli_request_destroy(req
);
48 /****************************************************************************
49 Query FS Info - SMBdskattr call (async recv)
50 ****************************************************************************/
51 static NTSTATUS
smb_raw_dskattr_recv(struct smbcli_request
*req
,
52 union smb_fsinfo
*fsinfo
)
54 if (!smbcli_request_receive(req
) ||
55 smbcli_request_is_error(req
)) {
59 SMBCLI_CHECK_WCT(req
, 5);
60 fsinfo
->dskattr
.out
.units_total
= SVAL(req
->in
.vwv
, VWV(0));
61 fsinfo
->dskattr
.out
.blocks_per_unit
= SVAL(req
->in
.vwv
, VWV(1));
62 fsinfo
->dskattr
.out
.block_size
= SVAL(req
->in
.vwv
, VWV(2));
63 fsinfo
->dskattr
.out
.units_free
= SVAL(req
->in
.vwv
, VWV(3));
66 return smbcli_request_destroy(req
);
70 /****************************************************************************
71 RAW_QFS_ trans2 interface via blobs (async send)
72 ****************************************************************************/
73 static struct smbcli_request
*smb_raw_qfsinfo_send(struct smbcli_tree
*tree
,
78 uint16_t setup
= TRANSACT2_QFSINFO
;
83 tp
.in
.setup_count
= 1;
85 tp
.in
.max_data
= 0xFFFF;
87 tp
.in
.data
= data_blob(NULL
, 0);
90 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 2);
91 if (!tp
.in
.params
.data
) {
94 SSVAL(tp
.in
.params
.data
, 0, info_level
);
96 return smb_raw_trans2_send(tree
, &tp
);
99 /****************************************************************************
100 RAW_QFS_ trans2 interface via blobs (async recv)
101 ****************************************************************************/
102 static NTSTATUS
smb_raw_qfsinfo_blob_recv(struct smbcli_request
*req
,
106 struct smb_trans2 tp
;
109 status
= smb_raw_trans2_recv(req
, mem_ctx
, &tp
);
111 if (NT_STATUS_IS_OK(status
)) {
112 (*blob
) = tp
.out
.data
;
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; \
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; \
134 /****************************************************************************
135 Query FSInfo raw interface (async send)
136 ****************************************************************************/
137 struct smbcli_request
*smb_raw_fsinfo_send(struct smbcli_tree
*tree
,
139 union smb_fsinfo
*fsinfo
)
143 /* handle the only non-trans2 call separately */
144 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
145 return smb_raw_dskattr_send(tree
, fsinfo
);
147 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
151 /* the headers map the trans2 levels direct to info levels */
152 info_level
= (uint16_t)fsinfo
->generic
.level
;
154 return smb_raw_qfsinfo_send(tree
, mem_ctx
, info_level
);
158 parse the fsinfo 'passthru' level replies
160 NTSTATUS
smb_raw_fsinfo_passthru_parse(DATA_BLOB blob
, TALLOC_CTX
*mem_ctx
,
161 enum smb_fsinfo_level level
,
162 union smb_fsinfo
*fsinfo
)
164 NTSTATUS status
= NT_STATUS_OK
;
167 /* parse the results */
169 case RAW_QFS_VOLUME_INFORMATION
:
170 QFS_CHECK_MIN_SIZE(18);
171 fsinfo
->volume_info
.out
.create_time
= smbcli_pull_nttime(blob
.data
, 0);
172 fsinfo
->volume_info
.out
.serial_number
= IVAL(blob
.data
, 8);
173 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
174 &fsinfo
->volume_info
.out
.volume_name
,
175 12, 18, STR_UNICODE
);
178 case RAW_QFS_SIZE_INFORMATION
:
180 fsinfo
->size_info
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
181 fsinfo
->size_info
.out
.avail_alloc_units
= BVAL(blob
.data
, 8);
182 fsinfo
->size_info
.out
.sectors_per_unit
= IVAL(blob
.data
, 16);
183 fsinfo
->size_info
.out
.bytes_per_sector
= IVAL(blob
.data
, 20);
186 case RAW_QFS_DEVICE_INFORMATION
:
188 fsinfo
->device_info
.out
.device_type
= IVAL(blob
.data
, 0);
189 fsinfo
->device_info
.out
.characteristics
= IVAL(blob
.data
, 4);
192 case RAW_QFS_ATTRIBUTE_INFORMATION
:
193 QFS_CHECK_MIN_SIZE(12);
194 fsinfo
->attribute_info
.out
.fs_attr
= IVAL(blob
.data
, 0);
195 fsinfo
->attribute_info
.out
.max_file_component_length
= IVAL(blob
.data
, 4);
196 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
197 &fsinfo
->attribute_info
.out
.fs_type
,
201 case RAW_QFS_QUOTA_INFORMATION
:
203 fsinfo
->quota_information
.out
.unknown
[0] = BVAL(blob
.data
, 0);
204 fsinfo
->quota_information
.out
.unknown
[1] = BVAL(blob
.data
, 8);
205 fsinfo
->quota_information
.out
.unknown
[2] = BVAL(blob
.data
, 16);
206 fsinfo
->quota_information
.out
.quota_soft
= BVAL(blob
.data
, 24);
207 fsinfo
->quota_information
.out
.quota_hard
= BVAL(blob
.data
, 32);
208 fsinfo
->quota_information
.out
.quota_flags
= BVAL(blob
.data
, 40);
211 case RAW_QFS_FULL_SIZE_INFORMATION
:
213 fsinfo
->full_size_information
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
214 fsinfo
->full_size_information
.out
.call_avail_alloc_units
= BVAL(blob
.data
, 8);
215 fsinfo
->full_size_information
.out
.actual_avail_alloc_units
= BVAL(blob
.data
, 16);
216 fsinfo
->full_size_information
.out
.sectors_per_unit
= IVAL(blob
.data
, 24);
217 fsinfo
->full_size_information
.out
.bytes_per_sector
= IVAL(blob
.data
, 28);
220 case RAW_QFS_OBJECTID_INFORMATION
: {
221 DATA_BLOB b2
= data_blob_const(blob
.data
, MIN(16, blob
.length
));
223 status
= GUID_from_ndr_blob(&b2
, &fsinfo
->objectid_information
.out
.guid
);
224 NT_STATUS_NOT_OK_RETURN(status
);
226 fsinfo
->objectid_information
.out
.unknown
[i
] = BVAL(blob
.data
, 16 + i
*8);
230 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
232 fsinfo
->sector_size_info
.out
.logical_bytes_per_sector
233 = IVAL(blob
.data
, 0);
234 fsinfo
->sector_size_info
.out
.phys_bytes_per_sector_atomic
235 = IVAL(blob
.data
, 4);
236 fsinfo
->sector_size_info
.out
.phys_bytes_per_sector_perf
237 = IVAL(blob
.data
, 8);
238 fsinfo
->sector_size_info
.out
.fs_effective_phys_bytes_per_sector_atomic
239 = IVAL(blob
.data
, 12);
240 fsinfo
->sector_size_info
.out
.flags
= IVAL(blob
.data
, 16);
241 fsinfo
->sector_size_info
.out
.byte_off_sector_align
242 = IVAL(blob
.data
, 20);
243 fsinfo
->sector_size_info
.out
.byte_off_partition_align
244 = IVAL(blob
.data
, 24);
249 status
= NT_STATUS_INVALID_INFO_CLASS
;
257 /****************************************************************************
258 Query FSInfo raw interface (async recv)
259 ****************************************************************************/
260 NTSTATUS
smb_raw_fsinfo_recv(struct smbcli_request
*req
,
262 union smb_fsinfo
*fsinfo
)
266 struct smbcli_session
*session
= req
?req
->session
:NULL
;
268 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
269 return smb_raw_dskattr_recv(req
, fsinfo
);
272 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
273 if (!NT_STATUS_IS_OK(status
)) {
277 /* parse the results */
278 switch (fsinfo
->generic
.level
) {
279 case RAW_QFS_GENERIC
:
280 case RAW_QFS_DSKATTR
:
284 case RAW_QFS_ALLOCATION
:
286 fsinfo
->allocation
.out
.fs_id
= IVAL(blob
.data
, 0);
287 fsinfo
->allocation
.out
.sectors_per_unit
= IVAL(blob
.data
, 4);
288 fsinfo
->allocation
.out
.total_alloc_units
= IVAL(blob
.data
, 8);
289 fsinfo
->allocation
.out
.avail_alloc_units
= IVAL(blob
.data
, 12);
290 fsinfo
->allocation
.out
.bytes_per_sector
= SVAL(blob
.data
, 16);
294 QFS_CHECK_MIN_SIZE(5);
295 fsinfo
->volume
.out
.serial_number
= IVAL(blob
.data
, 0);
296 smbcli_blob_pull_string(session
, mem_ctx
, &blob
,
297 &fsinfo
->volume
.out
.volume_name
,
298 4, 5, STR_LEN8BIT
| STR_NOALIGN
);
301 case RAW_QFS_VOLUME_INFO
:
302 case RAW_QFS_VOLUME_INFORMATION
:
303 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
304 RAW_QFS_VOLUME_INFORMATION
, fsinfo
);
306 case RAW_QFS_SIZE_INFO
:
307 case RAW_QFS_SIZE_INFORMATION
:
308 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
309 RAW_QFS_SIZE_INFORMATION
, fsinfo
);
311 case RAW_QFS_DEVICE_INFO
:
312 case RAW_QFS_DEVICE_INFORMATION
:
313 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
314 RAW_QFS_DEVICE_INFORMATION
, fsinfo
);
316 case RAW_QFS_ATTRIBUTE_INFO
:
317 case RAW_QFS_ATTRIBUTE_INFORMATION
:
318 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
319 RAW_QFS_ATTRIBUTE_INFORMATION
, fsinfo
);
321 case RAW_QFS_UNIX_INFO
:
323 fsinfo
->unix_info
.out
.major_version
= SVAL(blob
.data
, 0);
324 fsinfo
->unix_info
.out
.minor_version
= SVAL(blob
.data
, 2);
325 fsinfo
->unix_info
.out
.capability
= SVAL(blob
.data
, 4);
328 case RAW_QFS_QUOTA_INFORMATION
:
329 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
330 RAW_QFS_QUOTA_INFORMATION
, fsinfo
);
332 case RAW_QFS_FULL_SIZE_INFORMATION
:
333 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
334 RAW_QFS_FULL_SIZE_INFORMATION
, fsinfo
);
336 case RAW_QFS_OBJECTID_INFORMATION
:
337 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
338 RAW_QFS_OBJECTID_INFORMATION
, fsinfo
);
340 case RAW_QFS_SECTOR_SIZE_INFORMATION
:
341 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
342 RAW_QFS_SECTOR_SIZE_INFORMATION
, fsinfo
);
349 /****************************************************************************
350 Query FSInfo raw interface (sync interface)
351 ****************************************************************************/
352 _PUBLIC_ NTSTATUS
smb_raw_fsinfo(struct smbcli_tree
*tree
,
354 union smb_fsinfo
*fsinfo
)
356 struct smbcli_request
*req
= smb_raw_fsinfo_send(tree
, mem_ctx
, fsinfo
);
357 return smb_raw_fsinfo_recv(req
, mem_ctx
, fsinfo
);
360 /****************************************************************************
361 Set FSInfo raw interface (async recv)
362 ****************************************************************************/
363 static NTSTATUS
smb_raw_setfsinfo_recv(struct smbcli_request
*req
,
365 union smb_setfsinfo
*set_fsinfo
)
367 DATA_BLOB blob
= data_blob_null
;
370 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
371 return NT_STATUS_INVALID_PARAMETER
;
374 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
375 data_blob_free(&blob
);
379 /****************************************************************************
380 Set FSInfo raw interface (async send)
381 ****************************************************************************/
382 static struct smbcli_request
*smb_raw_setfsinfo_send(struct smbcli_tree
*tree
,
384 union smb_setfsinfo
*set_fsinfo
)
386 struct smb_trans2 tp
;
388 uint16_t setup
= TRANSACT2_SETFSINFO
;
390 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
396 tp
.in
.setup_count
= 1;
398 tp
.in
.max_data
= 0xFFFF;
399 tp
.in
.setup
= &setup
;
402 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 4);
403 if (!tp
.in
.params
.data
) {
406 info_level
= (uint16_t)set_fsinfo
->generic
.level
;
407 SSVAL(tp
.in
.params
.data
, 0, 0);
408 SSVAL(tp
.in
.params
.data
, 2, info_level
);
410 tp
.in
.data
= data_blob_talloc(mem_ctx
, NULL
, 12);
411 if (!tp
.in
.data
.data
) {
415 SSVAL(tp
.in
.data
.data
, 0, set_fsinfo
->unix_info
.in
.major_version
);
416 SSVAL(tp
.in
.data
.data
, 2, set_fsinfo
->unix_info
.in
.minor_version
);
417 SBVAL(tp
.in
.data
.data
, 4, set_fsinfo
->unix_info
.in
.capability
);
419 return smb_raw_trans2_send(tree
, &tp
);
422 /****************************************************************************
423 Set FSInfo raw interface (sync interface)
424 ****************************************************************************/
425 _PUBLIC_ NTSTATUS
smb_raw_setfsinfo(struct smbcli_tree
*tree
,
427 union smb_setfsinfo
*set_fsinfo
)
429 struct smbcli_request
*req
= smb_raw_setfsinfo_send(tree
, mem_ctx
, set_fsinfo
);
430 return smb_raw_setfsinfo_recv(req
, mem_ctx
, set_fsinfo
);