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);
37 if (!smbcli_request_send(req
)) {
38 smbcli_request_destroy(req
);
45 /****************************************************************************
46 Query FS Info - SMBdskattr call (async recv)
47 ****************************************************************************/
48 static NTSTATUS
smb_raw_dskattr_recv(struct smbcli_request
*req
,
49 union smb_fsinfo
*fsinfo
)
51 if (!smbcli_request_receive(req
) ||
52 smbcli_request_is_error(req
)) {
56 SMBCLI_CHECK_WCT(req
, 5);
57 fsinfo
->dskattr
.out
.units_total
= SVAL(req
->in
.vwv
, VWV(0));
58 fsinfo
->dskattr
.out
.blocks_per_unit
= SVAL(req
->in
.vwv
, VWV(1));
59 fsinfo
->dskattr
.out
.block_size
= SVAL(req
->in
.vwv
, VWV(2));
60 fsinfo
->dskattr
.out
.units_free
= SVAL(req
->in
.vwv
, VWV(3));
63 return smbcli_request_destroy(req
);
67 /****************************************************************************
68 RAW_QFS_ trans2 interface via blobs (async send)
69 ****************************************************************************/
70 static struct smbcli_request
*smb_raw_qfsinfo_send(struct smbcli_tree
*tree
,
75 uint16_t setup
= TRANSACT2_QFSINFO
;
80 tp
.in
.setup_count
= 1;
82 tp
.in
.max_data
= 0xFFFF;
84 tp
.in
.data
= data_blob(NULL
, 0);
87 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 2);
88 if (!tp
.in
.params
.data
) {
91 SSVAL(tp
.in
.params
.data
, 0, info_level
);
93 return smb_raw_trans2_send(tree
, &tp
);
96 /****************************************************************************
97 RAW_QFS_ trans2 interface via blobs (async recv)
98 ****************************************************************************/
99 static NTSTATUS
smb_raw_qfsinfo_blob_recv(struct smbcli_request
*req
,
103 struct smb_trans2 tp
;
106 status
= smb_raw_trans2_recv(req
, mem_ctx
, &tp
);
108 if (NT_STATUS_IS_OK(status
)) {
109 (*blob
) = tp
.out
.data
;
116 /* local macros to make the code more readable */
117 #define QFS_CHECK_MIN_SIZE(size) if (blob.length < (size)) { \
118 DEBUG(1,("Unexpected QFS reply size %d for level %u - expected min of %d\n", \
119 (int)blob.length, fsinfo->generic.level, (size))); \
120 status = NT_STATUS_INFO_LENGTH_MISMATCH; \
123 #define QFS_CHECK_SIZE(size) if (blob.length != (size)) { \
124 DEBUG(1,("Unexpected QFS reply size %d for level %u - expected %d\n", \
125 (int)blob.length, fsinfo->generic.level, (size))); \
126 status = NT_STATUS_INFO_LENGTH_MISMATCH; \
131 /****************************************************************************
132 Query FSInfo raw interface (async send)
133 ****************************************************************************/
134 struct smbcli_request
*smb_raw_fsinfo_send(struct smbcli_tree
*tree
,
136 union smb_fsinfo
*fsinfo
)
140 /* handle the only non-trans2 call separately */
141 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
142 return smb_raw_dskattr_send(tree
, fsinfo
);
144 if (fsinfo
->generic
.level
>= RAW_QFS_GENERIC
) {
148 /* the headers map the trans2 levels direct to info levels */
149 info_level
= (uint16_t)fsinfo
->generic
.level
;
151 return smb_raw_qfsinfo_send(tree
, mem_ctx
, info_level
);
155 parse the fsinfo 'passthru' level replies
157 NTSTATUS
smb_raw_fsinfo_passthru_parse(DATA_BLOB blob
, TALLOC_CTX
*mem_ctx
,
158 enum smb_fsinfo_level level
,
159 union smb_fsinfo
*fsinfo
)
161 NTSTATUS status
= NT_STATUS_OK
;
162 enum ndr_err_code ndr_err
;
165 /* parse the results */
167 case RAW_QFS_VOLUME_INFORMATION
:
168 QFS_CHECK_MIN_SIZE(18);
169 fsinfo
->volume_info
.out
.create_time
= smbcli_pull_nttime(blob
.data
, 0);
170 fsinfo
->volume_info
.out
.serial_number
= IVAL(blob
.data
, 8);
171 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
172 &fsinfo
->volume_info
.out
.volume_name
,
173 12, 18, STR_UNICODE
);
176 case RAW_QFS_SIZE_INFORMATION
:
178 fsinfo
->size_info
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
179 fsinfo
->size_info
.out
.avail_alloc_units
= BVAL(blob
.data
, 8);
180 fsinfo
->size_info
.out
.sectors_per_unit
= IVAL(blob
.data
, 16);
181 fsinfo
->size_info
.out
.bytes_per_sector
= IVAL(blob
.data
, 20);
184 case RAW_QFS_DEVICE_INFORMATION
:
186 fsinfo
->device_info
.out
.device_type
= IVAL(blob
.data
, 0);
187 fsinfo
->device_info
.out
.characteristics
= IVAL(blob
.data
, 4);
190 case RAW_QFS_ATTRIBUTE_INFORMATION
:
191 QFS_CHECK_MIN_SIZE(12);
192 fsinfo
->attribute_info
.out
.fs_attr
= IVAL(blob
.data
, 0);
193 fsinfo
->attribute_info
.out
.max_file_component_length
= IVAL(blob
.data
, 4);
194 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
195 &fsinfo
->attribute_info
.out
.fs_type
,
199 case RAW_QFS_QUOTA_INFORMATION
:
201 fsinfo
->quota_information
.out
.unknown
[0] = BVAL(blob
.data
, 0);
202 fsinfo
->quota_information
.out
.unknown
[1] = BVAL(blob
.data
, 8);
203 fsinfo
->quota_information
.out
.unknown
[2] = BVAL(blob
.data
, 16);
204 fsinfo
->quota_information
.out
.quota_soft
= BVAL(blob
.data
, 24);
205 fsinfo
->quota_information
.out
.quota_hard
= BVAL(blob
.data
, 32);
206 fsinfo
->quota_information
.out
.quota_flags
= BVAL(blob
.data
, 40);
209 case RAW_QFS_FULL_SIZE_INFORMATION
:
211 fsinfo
->full_size_information
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
212 fsinfo
->full_size_information
.out
.call_avail_alloc_units
= BVAL(blob
.data
, 8);
213 fsinfo
->full_size_information
.out
.actual_avail_alloc_units
= BVAL(blob
.data
, 16);
214 fsinfo
->full_size_information
.out
.sectors_per_unit
= IVAL(blob
.data
, 24);
215 fsinfo
->full_size_information
.out
.bytes_per_sector
= IVAL(blob
.data
, 28);
218 case RAW_QFS_OBJECTID_INFORMATION
:
220 ndr_err
= ndr_pull_struct_blob(&blob
, mem_ctx
, NULL
, &fsinfo
->objectid_information
.out
.guid
,
221 (ndr_pull_flags_fn_t
)ndr_pull_GUID
);
222 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err
)) {
223 status
= ndr_map_error2ntstatus(ndr_err
);
226 fsinfo
->objectid_information
.out
.unknown
[i
] = BVAL(blob
.data
, 16 + i
*8);
231 status
= NT_STATUS_INVALID_INFO_CLASS
;
239 /****************************************************************************
240 Query FSInfo raw interface (async recv)
241 ****************************************************************************/
242 NTSTATUS
smb_raw_fsinfo_recv(struct smbcli_request
*req
,
244 union smb_fsinfo
*fsinfo
)
248 struct smbcli_session
*session
= req
?req
->session
:NULL
;
250 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
251 return smb_raw_dskattr_recv(req
, fsinfo
);
254 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
255 if (!NT_STATUS_IS_OK(status
)) {
259 /* parse the results */
260 switch (fsinfo
->generic
.level
) {
261 case RAW_QFS_GENERIC
:
262 case RAW_QFS_DSKATTR
:
266 case RAW_QFS_ALLOCATION
:
268 fsinfo
->allocation
.out
.fs_id
= IVAL(blob
.data
, 0);
269 fsinfo
->allocation
.out
.sectors_per_unit
= IVAL(blob
.data
, 4);
270 fsinfo
->allocation
.out
.total_alloc_units
= IVAL(blob
.data
, 8);
271 fsinfo
->allocation
.out
.avail_alloc_units
= IVAL(blob
.data
, 12);
272 fsinfo
->allocation
.out
.bytes_per_sector
= SVAL(blob
.data
, 16);
276 QFS_CHECK_MIN_SIZE(5);
277 fsinfo
->volume
.out
.serial_number
= IVAL(blob
.data
, 0);
278 smbcli_blob_pull_string(session
, mem_ctx
, &blob
,
279 &fsinfo
->volume
.out
.volume_name
,
280 4, 5, STR_LEN8BIT
| STR_NOALIGN
);
283 case RAW_QFS_VOLUME_INFO
:
284 case RAW_QFS_VOLUME_INFORMATION
:
285 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
286 RAW_QFS_VOLUME_INFORMATION
, fsinfo
);
288 case RAW_QFS_SIZE_INFO
:
289 case RAW_QFS_SIZE_INFORMATION
:
290 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
291 RAW_QFS_SIZE_INFORMATION
, fsinfo
);
293 case RAW_QFS_DEVICE_INFO
:
294 case RAW_QFS_DEVICE_INFORMATION
:
295 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
296 RAW_QFS_DEVICE_INFORMATION
, fsinfo
);
298 case RAW_QFS_ATTRIBUTE_INFO
:
299 case RAW_QFS_ATTRIBUTE_INFORMATION
:
300 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
301 RAW_QFS_ATTRIBUTE_INFORMATION
, fsinfo
);
303 case RAW_QFS_UNIX_INFO
:
305 fsinfo
->unix_info
.out
.major_version
= SVAL(blob
.data
, 0);
306 fsinfo
->unix_info
.out
.minor_version
= SVAL(blob
.data
, 2);
307 fsinfo
->unix_info
.out
.capability
= SVAL(blob
.data
, 4);
310 case RAW_QFS_QUOTA_INFORMATION
:
311 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
312 RAW_QFS_QUOTA_INFORMATION
, fsinfo
);
314 case RAW_QFS_FULL_SIZE_INFORMATION
:
315 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
316 RAW_QFS_FULL_SIZE_INFORMATION
, fsinfo
);
318 case RAW_QFS_OBJECTID_INFORMATION
:
319 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
320 RAW_QFS_OBJECTID_INFORMATION
, fsinfo
);
327 /****************************************************************************
328 Query FSInfo raw interface (sync interface)
329 ****************************************************************************/
330 _PUBLIC_ NTSTATUS
smb_raw_fsinfo(struct smbcli_tree
*tree
,
332 union smb_fsinfo
*fsinfo
)
334 struct smbcli_request
*req
= smb_raw_fsinfo_send(tree
, mem_ctx
, fsinfo
);
335 return smb_raw_fsinfo_recv(req
, mem_ctx
, fsinfo
);