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
;
164 /* parse the results */
166 case RAW_QFS_VOLUME_INFORMATION
:
167 QFS_CHECK_MIN_SIZE(18);
168 fsinfo
->volume_info
.out
.create_time
= smbcli_pull_nttime(blob
.data
, 0);
169 fsinfo
->volume_info
.out
.serial_number
= IVAL(blob
.data
, 8);
170 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
171 &fsinfo
->volume_info
.out
.volume_name
,
172 12, 18, STR_UNICODE
);
175 case RAW_QFS_SIZE_INFORMATION
:
177 fsinfo
->size_info
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
178 fsinfo
->size_info
.out
.avail_alloc_units
= BVAL(blob
.data
, 8);
179 fsinfo
->size_info
.out
.sectors_per_unit
= IVAL(blob
.data
, 16);
180 fsinfo
->size_info
.out
.bytes_per_sector
= IVAL(blob
.data
, 20);
183 case RAW_QFS_DEVICE_INFORMATION
:
185 fsinfo
->device_info
.out
.device_type
= IVAL(blob
.data
, 0);
186 fsinfo
->device_info
.out
.characteristics
= IVAL(blob
.data
, 4);
189 case RAW_QFS_ATTRIBUTE_INFORMATION
:
190 QFS_CHECK_MIN_SIZE(12);
191 fsinfo
->attribute_info
.out
.fs_attr
= IVAL(blob
.data
, 0);
192 fsinfo
->attribute_info
.out
.max_file_component_length
= IVAL(blob
.data
, 4);
193 smbcli_blob_pull_string(NULL
, mem_ctx
, &blob
,
194 &fsinfo
->attribute_info
.out
.fs_type
,
198 case RAW_QFS_QUOTA_INFORMATION
:
200 fsinfo
->quota_information
.out
.unknown
[0] = BVAL(blob
.data
, 0);
201 fsinfo
->quota_information
.out
.unknown
[1] = BVAL(blob
.data
, 8);
202 fsinfo
->quota_information
.out
.unknown
[2] = BVAL(blob
.data
, 16);
203 fsinfo
->quota_information
.out
.quota_soft
= BVAL(blob
.data
, 24);
204 fsinfo
->quota_information
.out
.quota_hard
= BVAL(blob
.data
, 32);
205 fsinfo
->quota_information
.out
.quota_flags
= BVAL(blob
.data
, 40);
208 case RAW_QFS_FULL_SIZE_INFORMATION
:
210 fsinfo
->full_size_information
.out
.total_alloc_units
= BVAL(blob
.data
, 0);
211 fsinfo
->full_size_information
.out
.call_avail_alloc_units
= BVAL(blob
.data
, 8);
212 fsinfo
->full_size_information
.out
.actual_avail_alloc_units
= BVAL(blob
.data
, 16);
213 fsinfo
->full_size_information
.out
.sectors_per_unit
= IVAL(blob
.data
, 24);
214 fsinfo
->full_size_information
.out
.bytes_per_sector
= IVAL(blob
.data
, 28);
217 case RAW_QFS_OBJECTID_INFORMATION
: {
218 DATA_BLOB b2
= data_blob_const(blob
.data
, MIN(16, blob
.length
));
220 status
= GUID_from_ndr_blob(&b2
, &fsinfo
->objectid_information
.out
.guid
);
221 NT_STATUS_NOT_OK_RETURN(status
);
223 fsinfo
->objectid_information
.out
.unknown
[i
] = BVAL(blob
.data
, 16 + i
*8);
229 status
= NT_STATUS_INVALID_INFO_CLASS
;
237 /****************************************************************************
238 Query FSInfo raw interface (async recv)
239 ****************************************************************************/
240 NTSTATUS
smb_raw_fsinfo_recv(struct smbcli_request
*req
,
242 union smb_fsinfo
*fsinfo
)
246 struct smbcli_session
*session
= req
?req
->session
:NULL
;
248 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
249 return smb_raw_dskattr_recv(req
, fsinfo
);
252 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
253 if (!NT_STATUS_IS_OK(status
)) {
257 /* parse the results */
258 switch (fsinfo
->generic
.level
) {
259 case RAW_QFS_GENERIC
:
260 case RAW_QFS_DSKATTR
:
264 case RAW_QFS_ALLOCATION
:
266 fsinfo
->allocation
.out
.fs_id
= IVAL(blob
.data
, 0);
267 fsinfo
->allocation
.out
.sectors_per_unit
= IVAL(blob
.data
, 4);
268 fsinfo
->allocation
.out
.total_alloc_units
= IVAL(blob
.data
, 8);
269 fsinfo
->allocation
.out
.avail_alloc_units
= IVAL(blob
.data
, 12);
270 fsinfo
->allocation
.out
.bytes_per_sector
= SVAL(blob
.data
, 16);
274 QFS_CHECK_MIN_SIZE(5);
275 fsinfo
->volume
.out
.serial_number
= IVAL(blob
.data
, 0);
276 smbcli_blob_pull_string(session
, mem_ctx
, &blob
,
277 &fsinfo
->volume
.out
.volume_name
,
278 4, 5, STR_LEN8BIT
| STR_NOALIGN
);
281 case RAW_QFS_VOLUME_INFO
:
282 case RAW_QFS_VOLUME_INFORMATION
:
283 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
284 RAW_QFS_VOLUME_INFORMATION
, fsinfo
);
286 case RAW_QFS_SIZE_INFO
:
287 case RAW_QFS_SIZE_INFORMATION
:
288 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
289 RAW_QFS_SIZE_INFORMATION
, fsinfo
);
291 case RAW_QFS_DEVICE_INFO
:
292 case RAW_QFS_DEVICE_INFORMATION
:
293 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
294 RAW_QFS_DEVICE_INFORMATION
, fsinfo
);
296 case RAW_QFS_ATTRIBUTE_INFO
:
297 case RAW_QFS_ATTRIBUTE_INFORMATION
:
298 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
299 RAW_QFS_ATTRIBUTE_INFORMATION
, fsinfo
);
301 case RAW_QFS_UNIX_INFO
:
303 fsinfo
->unix_info
.out
.major_version
= SVAL(blob
.data
, 0);
304 fsinfo
->unix_info
.out
.minor_version
= SVAL(blob
.data
, 2);
305 fsinfo
->unix_info
.out
.capability
= SVAL(blob
.data
, 4);
308 case RAW_QFS_QUOTA_INFORMATION
:
309 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
310 RAW_QFS_QUOTA_INFORMATION
, fsinfo
);
312 case RAW_QFS_FULL_SIZE_INFORMATION
:
313 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
314 RAW_QFS_FULL_SIZE_INFORMATION
, fsinfo
);
316 case RAW_QFS_OBJECTID_INFORMATION
:
317 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
318 RAW_QFS_OBJECTID_INFORMATION
, fsinfo
);
325 /****************************************************************************
326 Query FSInfo raw interface (sync interface)
327 ****************************************************************************/
328 _PUBLIC_ NTSTATUS
smb_raw_fsinfo(struct smbcli_tree
*tree
,
330 union smb_fsinfo
*fsinfo
)
332 struct smbcli_request
*req
= smb_raw_fsinfo_send(tree
, mem_ctx
, fsinfo
);
333 return smb_raw_fsinfo_recv(req
, mem_ctx
, fsinfo
);
336 /****************************************************************************
337 Set FSInfo raw interface (async recv)
338 ****************************************************************************/
339 static NTSTATUS
smb_raw_setfsinfo_recv(struct smbcli_request
*req
,
341 union smb_setfsinfo
*set_fsinfo
)
343 DATA_BLOB blob
= data_blob_null
;
346 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
347 return NT_STATUS_INVALID_PARAMETER
;
350 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
351 data_blob_free(&blob
);
355 /****************************************************************************
356 Set FSInfo raw interface (async send)
357 ****************************************************************************/
358 static struct smbcli_request
*smb_raw_setfsinfo_send(struct smbcli_tree
*tree
,
360 union smb_setfsinfo
*set_fsinfo
)
362 struct smb_trans2 tp
;
364 uint16_t setup
= TRANSACT2_SETFSINFO
;
366 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
372 tp
.in
.setup_count
= 1;
374 tp
.in
.max_data
= 0xFFFF;
375 tp
.in
.setup
= &setup
;
378 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 4);
379 if (!tp
.in
.params
.data
) {
382 info_level
= (uint16_t)set_fsinfo
->generic
.level
;
383 SSVAL(tp
.in
.params
.data
, 0, 0);
384 SSVAL(tp
.in
.params
.data
, 2, info_level
);
386 tp
.in
.data
= data_blob_talloc(mem_ctx
, NULL
, 12);
387 if (!tp
.in
.data
.data
) {
391 SSVAL(tp
.in
.data
.data
, 0, set_fsinfo
->unix_info
.in
.major_version
);
392 SSVAL(tp
.in
.data
.data
, 2, set_fsinfo
->unix_info
.in
.minor_version
);
393 SBVAL(tp
.in
.data
.data
, 4, set_fsinfo
->unix_info
.in
.capability
);
395 return smb_raw_trans2_send(tree
, &tp
);
398 /****************************************************************************
399 Set FSInfo raw interface (sync interface)
400 ****************************************************************************/
401 _PUBLIC_ NTSTATUS
smb_raw_setfsinfo(struct smbcli_tree
*tree
,
403 union smb_setfsinfo
*set_fsinfo
)
405 struct smbcli_request
*req
= smb_raw_setfsinfo_send(tree
, mem_ctx
, set_fsinfo
);
406 return smb_raw_setfsinfo_recv(req
, mem_ctx
, set_fsinfo
);