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);
232 status
= NT_STATUS_INVALID_INFO_CLASS
;
240 /****************************************************************************
241 Query FSInfo raw interface (async recv)
242 ****************************************************************************/
243 NTSTATUS
smb_raw_fsinfo_recv(struct smbcli_request
*req
,
245 union smb_fsinfo
*fsinfo
)
249 struct smbcli_session
*session
= req
?req
->session
:NULL
;
251 if (fsinfo
->generic
.level
== RAW_QFS_DSKATTR
) {
252 return smb_raw_dskattr_recv(req
, fsinfo
);
255 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
256 if (!NT_STATUS_IS_OK(status
)) {
260 /* parse the results */
261 switch (fsinfo
->generic
.level
) {
262 case RAW_QFS_GENERIC
:
263 case RAW_QFS_DSKATTR
:
267 case RAW_QFS_ALLOCATION
:
269 fsinfo
->allocation
.out
.fs_id
= IVAL(blob
.data
, 0);
270 fsinfo
->allocation
.out
.sectors_per_unit
= IVAL(blob
.data
, 4);
271 fsinfo
->allocation
.out
.total_alloc_units
= IVAL(blob
.data
, 8);
272 fsinfo
->allocation
.out
.avail_alloc_units
= IVAL(blob
.data
, 12);
273 fsinfo
->allocation
.out
.bytes_per_sector
= SVAL(blob
.data
, 16);
277 QFS_CHECK_MIN_SIZE(5);
278 fsinfo
->volume
.out
.serial_number
= IVAL(blob
.data
, 0);
279 smbcli_blob_pull_string(session
, mem_ctx
, &blob
,
280 &fsinfo
->volume
.out
.volume_name
,
281 4, 5, STR_LEN8BIT
| STR_NOALIGN
);
284 case RAW_QFS_VOLUME_INFO
:
285 case RAW_QFS_VOLUME_INFORMATION
:
286 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
287 RAW_QFS_VOLUME_INFORMATION
, fsinfo
);
289 case RAW_QFS_SIZE_INFO
:
290 case RAW_QFS_SIZE_INFORMATION
:
291 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
292 RAW_QFS_SIZE_INFORMATION
, fsinfo
);
294 case RAW_QFS_DEVICE_INFO
:
295 case RAW_QFS_DEVICE_INFORMATION
:
296 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
297 RAW_QFS_DEVICE_INFORMATION
, fsinfo
);
299 case RAW_QFS_ATTRIBUTE_INFO
:
300 case RAW_QFS_ATTRIBUTE_INFORMATION
:
301 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
302 RAW_QFS_ATTRIBUTE_INFORMATION
, fsinfo
);
304 case RAW_QFS_UNIX_INFO
:
306 fsinfo
->unix_info
.out
.major_version
= SVAL(blob
.data
, 0);
307 fsinfo
->unix_info
.out
.minor_version
= SVAL(blob
.data
, 2);
308 fsinfo
->unix_info
.out
.capability
= SVAL(blob
.data
, 4);
311 case RAW_QFS_QUOTA_INFORMATION
:
312 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
313 RAW_QFS_QUOTA_INFORMATION
, fsinfo
);
315 case RAW_QFS_FULL_SIZE_INFORMATION
:
316 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
317 RAW_QFS_FULL_SIZE_INFORMATION
, fsinfo
);
319 case RAW_QFS_OBJECTID_INFORMATION
:
320 return smb_raw_fsinfo_passthru_parse(blob
, mem_ctx
,
321 RAW_QFS_OBJECTID_INFORMATION
, fsinfo
);
328 /****************************************************************************
329 Query FSInfo raw interface (sync interface)
330 ****************************************************************************/
331 _PUBLIC_ NTSTATUS
smb_raw_fsinfo(struct smbcli_tree
*tree
,
333 union smb_fsinfo
*fsinfo
)
335 struct smbcli_request
*req
= smb_raw_fsinfo_send(tree
, mem_ctx
, fsinfo
);
336 return smb_raw_fsinfo_recv(req
, mem_ctx
, fsinfo
);
339 /****************************************************************************
340 Set FSInfo raw interface (async recv)
341 ****************************************************************************/
342 static NTSTATUS
smb_raw_setfsinfo_recv(struct smbcli_request
*req
,
344 union smb_setfsinfo
*set_fsinfo
)
346 DATA_BLOB blob
= data_blob_null
;
349 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
350 return NT_STATUS_INVALID_PARAMETER
;
353 status
= smb_raw_qfsinfo_blob_recv(req
, mem_ctx
, &blob
);
354 data_blob_free(&blob
);
358 /****************************************************************************
359 Set FSInfo raw interface (async send)
360 ****************************************************************************/
361 static struct smbcli_request
*smb_raw_setfsinfo_send(struct smbcli_tree
*tree
,
363 union smb_setfsinfo
*set_fsinfo
)
365 struct smb_trans2 tp
;
367 uint16_t setup
= TRANSACT2_SETFSINFO
;
369 if (set_fsinfo
->generic
.level
!= RAW_SETFS_UNIX_INFO
) {
375 tp
.in
.setup_count
= 1;
377 tp
.in
.max_data
= 0xFFFF;
378 tp
.in
.setup
= &setup
;
381 tp
.in
.params
= data_blob_talloc(mem_ctx
, NULL
, 4);
382 if (!tp
.in
.params
.data
) {
385 info_level
= (uint16_t)set_fsinfo
->generic
.level
;
386 SSVAL(tp
.in
.params
.data
, 0, 0);
387 SSVAL(tp
.in
.params
.data
, 2, info_level
);
389 tp
.in
.data
= data_blob_talloc(mem_ctx
, NULL
, 12);
390 if (!tp
.in
.data
.data
) {
394 SSVAL(tp
.in
.data
.data
, 0, set_fsinfo
->unix_info
.in
.major_version
);
395 SSVAL(tp
.in
.data
.data
, 2, set_fsinfo
->unix_info
.in
.minor_version
);
396 SBVAL(tp
.in
.data
.data
, 4, set_fsinfo
->unix_info
.in
.capability
);
398 return smb_raw_trans2_send(tree
, &tp
);
401 /****************************************************************************
402 Set FSInfo raw interface (sync interface)
403 ****************************************************************************/
404 _PUBLIC_ NTSTATUS
smb_raw_setfsinfo(struct smbcli_tree
*tree
,
406 union smb_setfsinfo
*set_fsinfo
)
408 struct smbcli_request
*req
= smb_raw_setfsinfo_send(tree
, mem_ctx
, set_fsinfo
);
409 return smb_raw_setfsinfo_recv(req
, mem_ctx
, set_fsinfo
);