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****************************************************************************/ 30static struct smbcli_request *smb_raw_dskattr_send(struct smbcli_tree *tree, 31 union smb_fsinfo *fsinfo) 32{ 33 struct smbcli_request *req; 34 35 req = smbcli_request_setup(tree, SMBdskattr, 0, 0); 36 37 if (!smbcli_request_send(req)) { 38 smbcli_request_destroy(req); 39 return NULL; 40 } 41 42 return req; 43} 44 45/**************************************************************************** 46 Query FS Info - SMBdskattr call (async recv) 47****************************************************************************/ 48static NTSTATUS smb_raw_dskattr_recv(struct smbcli_request *req, 49 union smb_fsinfo *fsinfo) 50{ 51 if (!smbcli_request_receive(req) || 52 smbcli_request_is_error(req)) { 53 goto failed; 54 } 55 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)); 61 62failed: 63 return smbcli_request_destroy(req); 64} 65 66 67/**************************************************************************** 68 RAW_QFS_ trans2 interface via blobs (async send) 69****************************************************************************/ 70static struct smbcli_request *smb_raw_qfsinfo_send(struct smbcli_tree *tree, 71 TALLOC_CTX *mem_ctx, 72 uint16_t info_level) 73{ 74 struct smb_trans2 tp; 75 uint16_t setup = TRANSACT2_QFSINFO; 76 77 tp.in.max_setup = 0; 78 tp.in.flags = 0; 79 tp.in.timeout = 0; 80 tp.in.setup_count = 1; 81 tp.in.max_param = 0; 82 tp.in.max_data = 0xFFFF; 83 tp.in.setup = &setup; 84 tp.in.data = data_blob(NULL, 0); 85 tp.in.timeout = 0; 86 87 tp.in.params = data_blob_talloc(mem_ctx, NULL, 2); 88 if (!tp.in.params.data) { 89 return NULL; 90 } 91 SSVAL(tp.in.params.data, 0, info_level); 92 93 return smb_raw_trans2_send(tree, &tp); 94} 95 96/**************************************************************************** 97 RAW_QFS_ trans2 interface via blobs (async recv) 98****************************************************************************/ 99static NTSTATUS smb_raw_qfsinfo_blob_recv(struct smbcli_request *req, 100 TALLOC_CTX *mem_ctx, 101 DATA_BLOB *blob) 102{ 103 struct smb_trans2 tp; 104 NTSTATUS status; 105 106 status = smb_raw_trans2_recv(req, mem_ctx, &tp); 107 108 if (NT_STATUS_IS_OK(status)) { 109 (*blob) = tp.out.data; 110 } 111 112 return status; 113} 114 115 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; \ 121 goto failed; \ 122} 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; \ 127 goto failed; \ 128} 129 130 131/**************************************************************************** 132 Query FSInfo raw interface (async send) 133****************************************************************************/ 134struct smbcli_request *smb_raw_fsinfo_send(struct smbcli_tree *tree, 135 TALLOC_CTX *mem_ctx, 136 union smb_fsinfo *fsinfo) 137{ 138 uint16_t info_level; 139 140 /* handle the only non-trans2 call separately */ 141 if (fsinfo->generic.level == RAW_QFS_DSKATTR) { 142 return smb_raw_dskattr_send(tree, fsinfo); 143 } 144 if (fsinfo->generic.level >= RAW_QFS_GENERIC) { 145 return NULL; 146 } 147 148 /* the headers map the trans2 levels direct to info levels */ 149 info_level = (uint16_t)fsinfo->generic.level; 150 151 return smb_raw_qfsinfo_send(tree, mem_ctx, info_level); 152} 153 154/* 155 parse the fsinfo 'passthru' level replies 156*/ 157NTSTATUS smb_raw_fsinfo_passthru_parse(DATA_BLOB blob, TALLOC_CTX *mem_ctx, 158 enum smb_fsinfo_level level, 159 union smb_fsinfo *fsinfo) 160{ 161 NTSTATUS status = NT_STATUS_OK; 162 enum ndr_err_code ndr_err; 163 int i; 164 165 /* parse the results */ 166 switch (level) { 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); 174 break; 175 176 case RAW_QFS_SIZE_INFORMATION: 177 QFS_CHECK_SIZE(24); 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); 182 break; 183 184 case RAW_QFS_DEVICE_INFORMATION: 185 QFS_CHECK_SIZE(8); 186 fsinfo->device_info.out.device_type = IVAL(blob.data, 0); 187 fsinfo->device_info.out.characteristics = IVAL(blob.data, 4); 188 break; 189 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, 196 8, 12, STR_UNICODE); 197 break; 198 199 case RAW_QFS_QUOTA_INFORMATION: 200 QFS_CHECK_SIZE(48); 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); 207 break; 208 209 case RAW_QFS_FULL_SIZE_INFORMATION: 210 QFS_CHECK_SIZE(32); 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); 216 break; 217 218 case RAW_QFS_OBJECTID_INFORMATION: 219 QFS_CHECK_SIZE(64); 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); 224 } 225 for (i=0;i<6;i++) { 226 fsinfo->objectid_information.out.unknown[i] = BVAL(blob.data, 16 + i*8); 227 } 228 break; 229 230 default: 231 status = NT_STATUS_INVALID_INFO_CLASS; 232 } 233 234failed: 235 return status; 236} 237 238 239/**************************************************************************** 240 Query FSInfo raw interface (async recv) 241****************************************************************************/ 242NTSTATUS smb_raw_fsinfo_recv(struct smbcli_request *req, 243 TALLOC_CTX *mem_ctx, 244 union smb_fsinfo *fsinfo) 245{ 246 DATA_BLOB blob; 247 NTSTATUS status; 248 struct smbcli_session *session = req?req->session:NULL; 249 250 if (fsinfo->generic.level == RAW_QFS_DSKATTR) { 251 return smb_raw_dskattr_recv(req, fsinfo); 252 } 253 254 status = smb_raw_qfsinfo_blob_recv(req, mem_ctx, &blob); 255 if (!NT_STATUS_IS_OK(status)) { 256 return status; 257 } 258 259 /* parse the results */ 260 switch (fsinfo->generic.level) { 261 case RAW_QFS_GENERIC: 262 case RAW_QFS_DSKATTR: 263 /* handled above */ 264 break; 265 266 case RAW_QFS_ALLOCATION: 267 QFS_CHECK_SIZE(18); 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); 273 break; 274 275 case RAW_QFS_VOLUME: 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); 281 break; 282 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); 287 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); 292 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); 297 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); 302 303 case RAW_QFS_UNIX_INFO: 304 QFS_CHECK_SIZE(12); 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); 308 break; 309 310 case RAW_QFS_QUOTA_INFORMATION: 311 return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, 312 RAW_QFS_QUOTA_INFORMATION, fsinfo); 313 314 case RAW_QFS_FULL_SIZE_INFORMATION: 315 return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, 316 RAW_QFS_FULL_SIZE_INFORMATION, fsinfo); 317 318 case RAW_QFS_OBJECTID_INFORMATION: 319 return smb_raw_fsinfo_passthru_parse(blob, mem_ctx, 320 RAW_QFS_OBJECTID_INFORMATION, fsinfo); 321 } 322 323failed: 324 return status; 325} 326 327/**************************************************************************** 328 Query FSInfo raw interface (sync interface) 329****************************************************************************/ 330_PUBLIC_ NTSTATUS smb_raw_fsinfo(struct smbcli_tree *tree, 331 TALLOC_CTX *mem_ctx, 332 union smb_fsinfo *fsinfo) 333{ 334 struct smbcli_request *req = smb_raw_fsinfo_send(tree, mem_ctx, fsinfo); 335 return smb_raw_fsinfo_recv(req, mem_ctx, fsinfo); 336} 337